Fix nbtree posting list update desc output.
[pgsql.git] / meson.build
blobb69aaddb1f8cd94c88ef907d51b021490ee48483
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: '16devel',
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 compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 # meson's system names don't quite map to our "traditional" names. In some
163 # places we need the "traditional" name, e.g., for mapping
164 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
165 # that purpose.
166 portname = host_system
168 exesuffix = '' # overridden below where necessary
169 dlsuffix = '.so' # overridden below where necessary
170 library_path_var = 'LD_LIBRARY_PATH'
172 # Format of file to control exports from libraries, and how to pass them to
173 # the compiler. For export_fmt @0@ is the path to the file export file.
174 export_file_format = 'gnu'
175 export_file_suffix = 'list'
176 export_fmt = '-Wl,--version-script=@0@'
178 # Flags to add when linking a postgres extension, @0@ is path to
179 # the relevant object on the platform.
180 mod_link_args_fmt = []
182 memset_loop_limit = 1024
184 # Choice of shared memory and semaphore implementation
185 shmem_kind = 'sysv'
186 sema_kind = 'sysv'
188 # We implement support for some operating systems by pretending they're
189 # another. Map here, before determining system properties below
190 if host_system == 'dragonfly'
191   # apparently the most similar
192   host_system = 'netbsd'
193 endif
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 = '-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
240   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
241   # don't want because a) it's different from what we do for autoconf, b) it
242   # causes warnings starting in macOS Ventura
243   ldflags_mod += ['-Wl,-undefined,error']
245 elif host_system == 'freebsd'
246   sema_kind = 'unnamed_posix'
248 elif host_system == 'linux'
249   sema_kind = 'unnamed_posix'
250   cppflags += '-D_GNU_SOURCE'
252 elif host_system == 'netbsd'
253   # We must resolve all dynamic linking in the core server at program start.
254   # Otherwise the postmaster can self-deadlock due to signals interrupting
255   # resolution of calls, since NetBSD's linker takes a lock while doing that
256   # and some postmaster signal handlers do things that will also acquire that
257   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
258   # While there's not a hard reason to adopt these settings for our other
259   # executables, there's also little reason not to, so just add them to
260   # LDFLAGS.
261   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
263 elif host_system == 'openbsd'
264   # you're ok
266 elif host_system == 'sunos'
267   portname = 'solaris'
268   export_fmt = '-Wl,-M@0@'
269   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
271 elif host_system == 'windows'
272   portname = 'win32'
273   exesuffix = '.exe'
274   dlsuffix = '.dll'
275   library_path_var = ''
277   export_file_format = 'win'
278   export_file_suffix = 'def'
279   if cc.get_id() == 'msvc'
280     export_fmt = '/DEF:@0@'
281     mod_link_with_name = '@0@.exe.lib'
282   else
283     export_fmt = '@0@'
284     mod_link_with_name = 'lib@0@.exe.a'
285   endif
286   mod_link_args_fmt = ['@0@']
287   mod_link_with_dir = 'libdir'
289   shmem_kind = 'win32'
290   sema_kind = 'win32'
292   cdata.set('WIN32_STACK_RLIMIT', 4194304)
293   if cc.get_id() == 'msvc'
294     ldflags += '/INCREMENTAL:NO'
295     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
296     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
297   else
298     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
299     # Need to allow multiple definitions, we e.g. want to override getopt.
300     ldflags += '-Wl,--allow-multiple-definition'
301     # Ensure we get MSVC-like linking behavior.
302     ldflags += '-Wl,--disable-auto-import'
303   endif
305   os_deps += cc.find_library('ws2_32', required: true)
306   secur32_dep = cc.find_library('secur32', required: true)
307   backend_deps += secur32_dep
308   libpq_deps += secur32_dep
310   postgres_inc_d += 'src/include/port/win32'
311   if cc.get_id() == 'msvc'
312     postgres_inc_d += 'src/include/port/win32_msvc'
313   endif
315   windows = import('windows')
317 else
318   # XXX: Should we add an option to override the host_system as an escape
319   # hatch?
320   error('unknown host system: @0@'.format(host_system))
321 endif
325 ###############################################################
326 # Program paths
327 ###############################################################
329 # External programs
330 perl = find_program(get_option('PERL'), required: true, native: true)
331 python = find_program(get_option('PYTHON'), required: true, native: true)
332 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
333 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
334 sed = find_program(get_option('SED'), 'sed', native: true)
335 prove = find_program(get_option('PROVE'), native: true, required: false)
336 tar = find_program(get_option('TAR'), native: true)
337 gzip = find_program(get_option('GZIP'), native: true)
338 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
339 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
340 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
341 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
342 missing = find_program('config/missing', native: true)
343 cp = find_program('cp', required: false, native: true)
344 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
345 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
347 bison_flags = []
348 if bison.found()
349   bison_version_c = run_command(bison, '--version', check: true)
350   # bison version string helpfully is something like
351   # >>bison (GNU bison) 3.8.1<<
352   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
353   if bison_version.version_compare('>=3.0')
354     bison_flags += ['-Wno-deprecated']
355   endif
356 endif
357 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
358 bison_kw = {
359   'output': ['@BASENAME@.c', '@BASENAME@.h'],
360   'command': bison_cmd,
363 flex_flags = []
364 flex_wrapper = files('src/tools/pgflex')
365 flex_cmd = [python, flex_wrapper,
366   '--builddir', '@BUILD_ROOT@',
367   '--srcdir', '@SOURCE_ROOT@',
368   '--privatedir', '@PRIVATE_DIR@',
369   '--flex', flex, '--perl', perl,
370   '-i', '@INPUT@', '-o', '@OUTPUT0@',
373 wget = find_program('wget', required: false, native: true)
374 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
376 install_files = files('src/tools/install_files')
380 ###############################################################
381 # Path to meson (for tests etc)
382 ###############################################################
384 # NB: this should really be part of meson, see
385 # https://github.com/mesonbuild/meson/issues/8511
386 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
388 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
389   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
390     meson_binpath_r.returncode(),
391     meson_binpath_r.stdout(),
392     meson_binpath_r.stderr()))
393 endif
395 meson_binpath_s = meson_binpath_r.stdout().split('\n')
396 meson_binpath_len = meson_binpath_s.length()
398 if meson_binpath_len < 1
399   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
400 endif
402 i = 0
403 meson_impl = ''
404 meson_binpath = ''
405 meson_args = []
406 foreach e : meson_binpath_s
407   if i == 0
408     meson_impl = e
409   elif i == 1
410     meson_binpath = e
411   else
412     meson_args += e
413   endif
414   i += 1
415 endforeach
417 if meson_impl not in ['muon', 'meson']
418   error('unknown meson implementation "@0@"'.format(meson_impl))
419 endif
421 meson_bin = find_program(meson_binpath, native: true)
425 ###############################################################
426 # Option Handling
427 ###############################################################
429 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
431 blocksize = get_option('blocksize').to_int() * 1024
433 if get_option('segsize_blocks') != 0
434   if get_option('segsize') != 1
435     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
436   endif
438   segsize = get_option('segsize_blocks')
439 else
440   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
441 endif
443 cdata.set('BLCKSZ', blocksize, description:
444 '''Size of a disk block --- this also limits the size of a tuple. You can set
445    it bigger if you need bigger tuples (although TOAST should reduce the need
446    to have large tuples, since fields can be spread across multiple tuples).
447    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
448    currently 2^15 (32768). This is determined by the 15-bit widths of the
449    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
450    Changing BLCKSZ requires an initdb.''')
452 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
453 cdata.set('RELSEG_SIZE', segsize)
454 cdata.set('DEF_PGPORT', get_option('pgport'))
455 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
456 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
457 if get_option('system_tzdata') != ''
458   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
459 endif
463 ###############################################################
464 # Directories
465 ###############################################################
467 # These are set by the equivalent --xxxdir configure options.  We
468 # append "postgresql" to some of them, if the string does not already
469 # contain "pgsql" or "postgres", in order to avoid directory clutter.
471 pkg = 'postgresql'
473 dir_prefix = get_option('prefix')
475 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
477 dir_bin = get_option('bindir')
479 dir_data = get_option('datadir')
480 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
481   dir_data = dir_data / pkg
482 endif
484 dir_sysconf = get_option('sysconfdir')
485 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
486   dir_sysconf = dir_sysconf / pkg
487 endif
489 dir_lib = get_option('libdir')
491 dir_lib_pkg = dir_lib
492 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
493   dir_lib_pkg = dir_lib_pkg / pkg
494 endif
496 dir_pgxs = dir_lib_pkg / 'pgxs'
498 dir_include = get_option('includedir')
500 dir_include_pkg = dir_include
501 dir_include_pkg_rel = ''
502 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
503   dir_include_pkg = dir_include_pkg / pkg
504   dir_include_pkg_rel = pkg
505 endif
507 dir_man = get_option('mandir')
509 # FIXME: These used to be separately configurable - worth adding?
510 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
511 dir_doc_html = dir_doc / 'html'
513 dir_locale = get_option('localedir')
516 # Derived values
517 dir_bitcode = dir_lib_pkg / 'bitcode'
518 dir_include_internal = dir_include_pkg / 'internal'
519 dir_include_server = dir_include_pkg / 'server'
520 dir_include_extension = dir_include_server / 'extension'
521 dir_data_extension = dir_data / 'extension'
525 ###############################################################
526 # Search paths, preparation for compiler tests
528 # NB: Arguments added later are not automatically used for subsequent
529 # configuration-time checks (so they are more isolated). If they should be
530 # used, they need to be added to test_c_args as well.
531 ###############################################################
533 postgres_inc = [include_directories(postgres_inc_d)]
534 test_lib_d = postgres_lib_d
535 test_c_args = cppflags + cflags
539 ###############################################################
540 # Library: bsd-auth
541 ###############################################################
543 bsd_authopt = get_option('bsd_auth')
544 bsd_auth = not_found_dep
545 if cc.check_header('bsd_auth.h', required: bsd_authopt,
546     args: test_c_args, include_directories: postgres_inc)
547   cdata.set('USE_BSD_AUTH', 1)
548   bsd_auth = declare_dependency()
549 endif
553 ###############################################################
554 # Library: bonjour
556 # For now don't search for DNSServiceRegister in a library - only Apple's
557 # Bonjour implementation, which is always linked, works.
558 ###############################################################
560 bonjouropt = get_option('bonjour')
561 bonjour = dependency('', required : false)
562 if cc.check_header('dns_sd.h', required: bonjouropt,
563     args: test_c_args, include_directories: postgres_inc) and \
564    cc.has_function('DNSServiceRegister',
565     args: test_c_args, include_directories: postgres_inc)
566   cdata.set('USE_BONJOUR', 1)
567   bonjour = declare_dependency()
568 endif
572 ###############################################################
573 # Option: docs in HTML and man page format
574 ###############################################################
576 docs_opt = get_option('docs')
577 docs_dep = not_found_dep
578 if not docs_opt.disabled()
579   if xmllint_bin.found() and xsltproc_bin.found()
580     docs_dep = declare_dependency()
581   elif docs_opt.enabled()
582     error('missing required tools for docs in HTML / man page format')
583   endif
584 endif
588 ###############################################################
589 # Option: docs in PDF format
590 ###############################################################
592 docs_pdf_opt = get_option('docs_pdf')
593 docs_pdf_dep = not_found_dep
594 if not docs_pdf_opt.disabled()
595   fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
596   if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
597     docs_pdf_dep = declare_dependency()
598   elif docs_pdf_opt.enabled()
599     error('missing required tools for docs in PDF format')
600   endif
601 endif
605 ###############################################################
606 # Library: GSSAPI
607 ###############################################################
609 gssapiopt = get_option('gssapi')
610 krb_srvtab = ''
611 have_gssapi = false
612 if not gssapiopt.disabled()
613   gssapi = dependency('krb5-gssapi', required: gssapiopt)
614   have_gssapi = gssapi.found()
616   if not have_gssapi
617   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
618       args: test_c_args, include_directories: postgres_inc)
619     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
620   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
621     cdata.set('HAVE_GSSAPI_H', 1)
622   else
623     have_gssapi = false
624   endif
626   if not have_gssapi
627   elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
628       args: test_c_args, include_directories: postgres_inc)
629     cdata.set('ENABLE_GSS', 1)
631     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
632     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
633   elif gssapiopt.enabled()
634     error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
635   else
636     have_gssapi = false
637   endif
638 endif
639 if not have_gssapi
640   gssapi = not_found_dep
641 endif
645 ###############################################################
646 # Library: ldap
647 ###############################################################
649 ldapopt = get_option('ldap')
650 if ldapopt.disabled()
651   ldap = not_found_dep
652   ldap_r = not_found_dep
653 elif host_system == 'windows'
654   ldap = cc.find_library('wldap32', required: ldapopt)
655   ldap_r = ldap
656 else
657   # macos framework dependency is buggy for ldap (one can argue whether it's
658   # Apple's or meson's fault), leading to an endless recursion with ldap.h
659   # including itself. See https://github.com/mesonbuild/meson/issues/10002
660   # Luckily we only need pkg-config support, so the workaround isn't
661   # complicated.
662   ldap = dependency('ldap', method: 'pkg-config', required: false)
663   ldap_r = ldap
665   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
666   # installed
667   if not ldap.found()
668     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
669       has_headers: 'ldap.h', header_include_directories: postgres_inc)
671     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
672     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
673     # library from a separate OpenLDAP installation).  The most reliable
674     # way to check that is to check for a function introduced in 2.5.
675     if not ldap.found()
676       # don't have ldap, we shouldn't check for ldap_r
677     elif cc.has_function('ldap_verify_credentials',
678         dependencies: ldap, args: test_c_args)
679       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
680     else
682       # Use ldap_r for FE if available, else assume ldap is thread-safe.
683       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
684         has_headers: 'ldap.h', header_include_directories: postgres_inc)
685       if not ldap_r.found()
686         ldap_r = ldap
687       else
688         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
689         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
690       endif
692       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
693       # process.  Check for OpenLDAP versions known not to tolerate doing so;
694       # assume non-OpenLDAP implementations are safe.  The dblink test suite
695       # exercises the hazardous interaction directly.
696       compat_test_code = '''
697 #include <ldap.h>
698 #if !defined(LDAP_VENDOR_VERSION) || \
699      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
700       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
701 choke me
702 #endif
704       if not cc.compiles(compat_test_code,
705           name: 'LDAP implementation compatible',
706           dependencies: ldap, args: test_c_args)
707         warning('''
708 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
709 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
710 *** also uses LDAP will crash on exit.''')
711       endif
712     endif
713   endif
715   # XXX: this shouldn't be tested in the windows case, but should be tested in
716   # the dependency() success case
717   if ldap.found() and cc.has_function('ldap_initialize',
718       dependencies: ldap, args: test_c_args)
719     cdata.set('HAVE_LDAP_INITIALIZE', 1)
720   endif
721 endif
723 if ldap.found()
724   assert(ldap_r.found())
725   cdata.set('USE_LDAP', 1)
726 else
727   assert(not ldap_r.found())
728 endif
732 ###############################################################
733 # Library: LLVM
734 ###############################################################
736 llvmopt = get_option('llvm')
737 if not llvmopt.disabled()
738   add_languages('cpp', required: true, native: false)
739   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
741   if llvm.found()
743     cdata.set('USE_LLVM', 1)
745     cpp = meson.get_compiler('cpp')
747     llvm_binpath = llvm.get_variable(configtool: 'bindir')
749     ccache = find_program('ccache', native: true, required: false)
750     clang = find_program(llvm_binpath / 'clang', required: true)
751   endif
752 else
753   llvm = not_found_dep
754 endif
758 ###############################################################
759 # Library: icu
760 ###############################################################
762 icuopt = get_option('icu')
763 if not icuopt.disabled()
764   icu = dependency('icu-uc', required: icuopt.enabled())
765   icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
767   if icu.found()
768     cdata.set('USE_ICU', 1)
769   endif
771 else
772   icu = not_found_dep
773   icu_i18n = not_found_dep
774 endif
778 ###############################################################
779 # Library: libxml
780 ###############################################################
782 libxmlopt = get_option('libxml')
783 if not libxmlopt.disabled()
784   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
786   if libxml.found()
787     cdata.set('USE_LIBXML', 1)
788   endif
789 else
790   libxml = not_found_dep
791 endif
795 ###############################################################
796 # Library: libxslt
797 ###############################################################
799 libxsltopt = get_option('libxslt')
800 if not libxsltopt.disabled()
801   libxslt = dependency('libxslt', required: libxsltopt)
803   if libxslt.found()
804     cdata.set('USE_LIBXSLT', 1)
805   endif
806 else
807   libxslt = not_found_dep
808 endif
812 ###############################################################
813 # Library: lz4
814 ###############################################################
816 lz4opt = get_option('lz4')
817 if not lz4opt.disabled()
818   lz4 = dependency('liblz4', required: lz4opt)
820   if lz4.found()
821     cdata.set('USE_LZ4', 1)
822     cdata.set('HAVE_LIBLZ4', 1)
823   endif
825 else
826   lz4 = not_found_dep
827 endif
831 ###############################################################
832 # Library: Tcl (for pltcl)
834 # NB: tclConfig.sh is used in autoconf build for getting
835 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
836 # variables. For now we have not seen a need to copy
837 # that behaviour to the meson build.
838 ###############################################################
840 tclopt = get_option('pltcl')
841 tcl_version = get_option('tcl_version')
842 tcl_dep = not_found_dep
843 if not tclopt.disabled()
845   # via pkg-config
846   tcl_dep = dependency(tcl_version, required: false)
848   if not tcl_dep.found()
849     tcl_dep = cc.find_library(tcl_version,
850       required: tclopt,
851       dirs: test_lib_d)
852   endif
854   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
855     tcl_dep = not_found_dep
856   endif
857 endif
861 ###############################################################
862 # Library: pam
863 ###############################################################
865 pamopt = get_option('pam')
866 if not pamopt.disabled()
867   pam = dependency('pam', required: false)
869   if not pam.found()
870     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
871   endif
873   if pam.found()
874     pam_header_found = false
876     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
877     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
878         args: test_c_args, include_directories: postgres_inc)
879       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
880       pam_header_found = true
881     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
882         args: test_c_args, include_directories: postgres_inc)
883       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
884       pam_header_found = true
885     endif
887     if pam_header_found
888       cdata.set('USE_PAM', 1)
889     else
890       pam = not_found_dep
891     endif
892   endif
893 else
894   pam = not_found_dep
895 endif
899 ###############################################################
900 # Library: Perl (for plperl)
901 ###############################################################
903 perlopt = get_option('plperl')
904 perl_dep = not_found_dep
905 if not perlopt.disabled()
906   perl_may_work = true
908   # First verify that perl has the necessary dependencies installed
909   perl_mods = run_command(
910     [perl,
911      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
912      '-e', ''],
913     check: false)
914   if perl_mods.returncode() != 0
915     perl_may_work = false
916     perl_msg = 'perl installation does not have the required modules'
917   endif
919   # Then inquire perl about its configuration
920   if perl_may_work
921     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
922     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
923     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
924     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
925     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
927     perl_inc_dir = '@0@/CORE'.format(archlibexp)
929     if perlversion.version_compare('< 5.14')
930       perl_may_work = false
931       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
932     elif useshrplib != 'true'
933       perl_may_work = false
934       perl_msg = 'need a shared perl'
935     endif
936   endif
938   if perl_may_work
939     # On most platforms, archlibexp is also where the Perl include files live ...
940     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
941     # ... but on newer macOS versions, we must use -iwithsysroot to look
942     # under sysroot
943     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
944        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
945       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
946     endif
948     # check compiler finds header
949     if not cc.has_header('perl.h', required: false,
950         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
951       perl_may_work = false
952       perl_msg = 'missing perl.h'
953     endif
954   endif
956   if perl_may_work
957     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
959     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
960     foreach flag : perl_ccflags_r.split(' ')
961       if flag.startswith('-D') and \
962           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
963         perl_ccflags += flag
964       endif
965     endforeach
967     if host_system == 'windows'
968       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
970       if cc.get_id() == 'msvc'
971         # prevent binary mismatch between MSVC built plperl and Strawberry or
972         # msys ucrt perl libraries
973         perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
974       endif
975     endif
977     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
978     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
980     # We are after Embed's ldopts, but without the subset mentioned in
981     # Config's ccdlflags and ldflags.  (Those are the choices of those who
982     # built the Perl installation, which are not necessarily appropriate
983     # for building PostgreSQL.)
984     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
985     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
986     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
988     perl_ldopts = []
989     foreach ldopt : ldopts.split(' ')
990       if ldopt == '' or ldopt in undesired
991         continue
992       endif
994       perl_ldopts += ldopt.strip('"')
995     endforeach
997     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
998     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1000     perl_dep_int = declare_dependency(
1001       compile_args: perl_ccflags,
1002       link_args: perl_ldopts,
1003       version: perlversion,
1004     )
1006     # While we're at it, check that we can link to libperl.
1007     # On most platforms, if perl.h is there then libperl.so will be too, but
1008     # at this writing Debian packages them separately.
1009     perl_link_test = '''
1010 /* see plperl.h */
1011 #ifdef _MSC_VER
1012 #define __inline__ inline
1013 #endif
1014 #include <EXTERN.h>
1015 #include <perl.h>
1016 int main(void)
1018 perl_alloc();
1019 }'''
1020     if not cc.links(perl_link_test, name: 'libperl',
1021           args: test_c_args + perl_ccflags + perl_ldopts,
1022           include_directories: postgres_inc)
1023       perl_may_work = false
1024       perl_msg = 'missing libperl'
1025     endif
1027   endif # perl_may_work
1029   if perl_may_work
1030     perl_dep = perl_dep_int
1031   else
1032     if perlopt.enabled()
1033       error('dependency plperl failed: @0@'.format(perl_msg))
1034     else
1035       message('disabling optional dependency plperl: @0@'.format(perl_msg))
1036     endif
1037   endif
1038 endif
1042 ###############################################################
1043 # Library: Python (for plpython)
1044 ###############################################################
1046 pyopt = get_option('plpython')
1047 if not pyopt.disabled()
1048   pm = import('python')
1049   python3_inst = pm.find_installation(required: pyopt.enabled())
1050   python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
1051   if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
1052     python3_dep = not_found_dep
1053   endif
1054 else
1055   python3_dep = not_found_dep
1056 endif
1060 ###############################################################
1061 # Library: Readline
1062 ###############################################################
1064 if not get_option('readline').disabled()
1065   libedit_preferred = get_option('libedit_preferred')
1066   # Set the order of readline dependencies
1067   check_readline_deps = libedit_preferred ? \
1068     ['libedit', 'readline'] : ['readline', 'libedit']
1070   foreach readline_dep : check_readline_deps
1071     readline = dependency(readline_dep, required: false)
1072     if not readline.found()
1073       readline = cc.find_library(readline_dep,
1074         required: get_option('readline').enabled(),
1075         dirs: test_lib_d)
1076     endif
1077     if readline.found()
1078       break
1079     endif
1080   endforeach
1082   if readline.found()
1083     cdata.set('HAVE_LIBREADLINE', 1)
1085     editline_prefix = {
1086       'header_prefix': 'editline/',
1087       'flag_prefix': 'EDITLINE_',
1088     }
1089     readline_prefix = {
1090       'header_prefix': 'readline/',
1091       'flag_prefix': 'READLINE_',
1092     }
1093     default_prefix = {
1094       'header_prefix': '',
1095       'flag_prefix': '',
1096     }
1098     # Set the order of prefixes
1099     prefixes = libedit_preferred ? \
1100       [editline_prefix, default_prefix, readline_prefix] : \
1101       [readline_prefix, default_prefix, editline_prefix]
1103     at_least_one_header_found = false
1104     foreach header : ['history', 'readline']
1105       is_found = false
1106       foreach prefix : prefixes
1107         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1108         # Check history.h and readline.h
1109         if not is_found and cc.has_header(header_file,
1110             args: test_c_args, include_directories: postgres_inc,
1111             dependencies: [readline], required: false)
1112           if header == 'readline'
1113             readline_h = header_file
1114           endif
1115           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1116           is_found = true
1117           at_least_one_header_found = true
1118         endif
1119       endforeach
1120     endforeach
1122     if not at_least_one_header_found
1123       error('''readline header not found
1124 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1125 failure. It is possible the compiler isn't looking in the proper directory.
1126 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1127     endif
1129     check_funcs = [
1130       'append_history',
1131       'history_truncate_file',
1132       'rl_completion_matches',
1133       'rl_filename_completion_function',
1134       'rl_reset_screen_size',
1135       'rl_variable_bind',
1136     ]
1138     foreach func : check_funcs
1139       found = cc.has_function(func, dependencies: [readline],
1140         args: test_c_args, include_directories: postgres_inc)
1141       cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1142     endforeach
1144     check_vars = [
1145       'rl_completion_suppress_quote',
1146       'rl_filename_quote_characters',
1147       'rl_filename_quoting_function',
1148     ]
1150     foreach var : check_vars
1151       cdata.set('HAVE_'+var.to_upper(),
1152         cc.has_header_symbol(readline_h, var,
1153           args: test_c_args, include_directories: postgres_inc,
1154           prefix: '#include <stdio.h>',
1155           dependencies: [readline]) ? 1 : false)
1156     endforeach
1158     # If found via cc.find_library() ensure headers are found when using the
1159     # dependency. On meson < 0.57 one cannot do compiler checks using the
1160     # dependency returned by declare_dependency(), so we can't do this above.
1161     if readline.type_name() == 'library'
1162       readline = declare_dependency(dependencies: readline,
1163         include_directories: postgres_inc)
1164     endif
1166     # On windows with mingw readline requires auto-import to successfully
1167     # link, as the headers don't use declspec(dllimport)
1168     if host_system == 'windows' and cc.get_id() != 'msvc'
1169       readline = declare_dependency(dependencies: readline,
1170         link_args: '-Wl,--enable-auto-import')
1171     endif
1172   endif
1174   # XXX: Figure out whether to implement mingw warning equivalent
1175 else
1176   readline = not_found_dep
1177 endif
1181 ###############################################################
1182 # Library: selinux
1183 ###############################################################
1185 selinux = not_found_dep
1186 selinuxopt = get_option('selinux')
1187 if meson.version().version_compare('>=0.59')
1188   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1189 endif
1190 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1191 cdata.set('HAVE_LIBSELINUX',
1192   selinux.found() ? 1 : false)
1196 ###############################################################
1197 # Library: systemd
1198 ###############################################################
1200 systemd = not_found_dep
1201 systemdopt = get_option('systemd')
1202 if meson.version().version_compare('>=0.59')
1203   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1204 endif
1205 systemd = dependency('libsystemd', required: systemdopt)
1206 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1210 ###############################################################
1211 # Library: SSL
1212 ###############################################################
1214 ssl = not_found_dep
1215 ssl_library = 'none'
1216 sslopt = get_option('ssl')
1218 if sslopt == 'auto' and auto_features.disabled()
1219   sslopt = 'none'
1220 endif
1222 if sslopt in ['auto', 'openssl']
1223   openssl_required = (sslopt == 'openssl')
1225   # Try to find openssl via pkg-config et al, if that doesn't work
1226   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1227   # the library names that we know about.
1229   # via pkg-config et al
1230   ssl = dependency('openssl', required: false)
1231   # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1232   # we pass cc.find_library() results if necessary
1233   ssl_int = []
1235   # via library + headers
1236   if not ssl.found()
1237     ssl_lib = cc.find_library('ssl',
1238       dirs: test_lib_d,
1239       header_include_directories: postgres_inc,
1240       has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1241       required: openssl_required)
1242     crypto_lib = cc.find_library('crypto',
1243       dirs: test_lib_d,
1244       required: openssl_required)
1245     if ssl_lib.found() and crypto_lib.found()
1246       ssl_int = [ssl_lib, crypto_lib]
1247       ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1248     endif
1249   elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1250        cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1251     ssl_int = [ssl]
1252   else
1253     ssl = not_found_dep
1254   endif
1256   if ssl.found()
1257     check_funcs = [
1258       ['CRYPTO_new_ex_data', {'required': true}],
1259       ['SSL_new', {'required': true}],
1261       # Functions introduced in OpenSSL 1.0.2.
1262       ['X509_get_signature_nid'],
1263       ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1265       # Functions introduced in OpenSSL 1.1.0. We used to check for
1266       # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1267       # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1268       # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1269       # functions.
1270       ['OPENSSL_init_ssl'],
1271       ['BIO_get_data'],
1272       ['BIO_meth_new'],
1273       ['ASN1_STRING_get0_data'],
1274       ['HMAC_CTX_new'],
1275       ['HMAC_CTX_free'],
1277       # OpenSSL versions before 1.1.0 required setting callback functions, for
1278       # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1279       # function was removed.
1280       ['CRYPTO_lock'],
1282       # Function introduced in OpenSSL 1.1.1
1283       ['X509_get_signature_info'],
1284     ]
1286     are_openssl_funcs_complete = true
1287     foreach c : check_funcs
1288       func = c.get(0)
1289       val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1290       required = c.get(1, {}).get('required', false)
1291       if required and not val
1292         are_openssl_funcs_complete = false
1293         if openssl_required
1294           error('openssl function @0@ is required'.format(func))
1295         endif
1296         break
1297       elif not required
1298         cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1299       endif
1300     endforeach
1302     if are_openssl_funcs_complete
1303       cdata.set('USE_OPENSSL', 1,
1304                 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1305       cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1306                 description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1307       ssl_library = 'openssl'
1308     else
1309       ssl = not_found_dep
1310     endif
1311   endif
1312 endif
1314 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1315   error('no SSL library found')
1316 endif
1320 ###############################################################
1321 # Library: uuid
1322 ###############################################################
1324 uuidopt = get_option('uuid')
1325 if uuidopt != 'none'
1326   uuidname = uuidopt.to_upper()
1327   if uuidopt == 'e2fs'
1328     uuid = dependency('uuid', required: true)
1329     uuidfunc = 'uuid_generate'
1330     uuidheader = 'uuid/uuid.h'
1331   elif uuidopt == 'bsd'
1332     # libc should have uuid function
1333     uuid = declare_dependency()
1334     uuidfunc = 'uuid_to_string'
1335     uuidheader = 'uuid.h'
1336   elif uuidopt == 'ossp'
1337     uuid = dependency('ossp-uuid', required: true)
1338     uuidfunc = 'uuid_export'
1339     uuidheader = 'uuid.h'
1340   else
1341     error('huh')
1342   endif
1344   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1345     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1346   endif
1347   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1349   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1350            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1351 else
1352   uuid = not_found_dep
1353 endif
1357 ###############################################################
1358 # Library: zlib
1359 ###############################################################
1361 zlibopt = get_option('zlib')
1362 zlib = not_found_dep
1363 if not zlibopt.disabled()
1364   zlib_t = dependency('zlib', required: zlibopt)
1366   if zlib_t.type_name() == 'internal'
1367     # if fallback was used, we don't need to test if headers are present (they
1368     # aren't built yet, so we can't test)
1369     zlib = zlib_t
1370   elif not zlib_t.found()
1371     warning('did not find zlib')
1372   elif not cc.has_header('zlib.h',
1373       args: test_c_args, include_directories: postgres_inc,
1374       dependencies: [zlib_t], required: zlibopt.enabled())
1375     warning('zlib header not found')
1376   elif not cc.has_type('z_streamp',
1377       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1378       args: test_c_args, include_directories: postgres_inc)
1379     if zlibopt.enabled()
1380       error('zlib version is too old')
1381     else
1382       warning('zlib version is too old')
1383     endif
1384   else
1385     zlib = zlib_t
1386   endif
1388   if zlib.found()
1389     cdata.set('HAVE_LIBZ', 1)
1390   endif
1391 endif
1395 ###############################################################
1396 # Library: tap test dependencies
1397 ###############################################################
1399 # Check whether tap tests are enabled or not
1400 tap_tests_enabled = false
1401 tapopt = get_option('tap_tests')
1402 if not tapopt.disabled()
1403   # Checking for perl modules for tap tests
1404   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1405   if perl_ipc_run_check.returncode() != 0
1406     message(perl_ipc_run_check.stderr().strip())
1407     if tapopt.enabled()
1408       error('Additional Perl modules are required to run TAP tests.')
1409     else
1410       warning('Additional Perl modules are required to run TAP tests.')
1411     endif
1412   else
1413     tap_tests_enabled = true
1414   endif
1415 endif
1419 ###############################################################
1420 # Library: zstd
1421 ###############################################################
1423 zstdopt = get_option('zstd')
1424 if not zstdopt.disabled()
1425   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1427   if zstd.found()
1428     cdata.set('USE_ZSTD', 1)
1429     cdata.set('HAVE_LIBZSTD', 1)
1430   endif
1432 else
1433   zstd = not_found_dep
1434 endif
1438 ###############################################################
1439 # Compiler tests
1440 ###############################################################
1442 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1443 # unnecessarily, because we optionally rely on newer features.
1444 c99_test = '''
1445 #include <stdbool.h>
1446 #include <complex.h>
1447 #include <tgmath.h>
1448 #include <inttypes.h>
1450 struct named_init_test {
1451   int a;
1452   int b;
1455 extern void structfunc(struct named_init_test);
1457 int main(int argc, char **argv)
1459   struct named_init_test nit = {
1460     .a = 3,
1461     .b = 5,
1462   };
1464   for (int loop_var = 0; loop_var < 3; loop_var++)
1465   {
1466     nit.a += nit.b;
1467   }
1469   structfunc((struct named_init_test){1, 0});
1471   return nit.a != 0;
1475 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1476   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1477         args: test_c_args + ['-std=c99'])
1478     test_c_args += '-std=c99'
1479     cflags += '-std=c99'
1480   else
1481     error('C compiler does not support C99')
1482   endif
1483 endif
1485 sizeof_long = cc.sizeof('long', args: test_c_args)
1486 cdata.set('SIZEOF_LONG', sizeof_long)
1487 if sizeof_long == 8
1488   cdata.set('HAVE_LONG_INT_64', 1)
1489   cdata.set('PG_INT64_TYPE', 'long int')
1490   cdata.set_quoted('INT64_MODIFIER', 'l')
1491 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1492   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1493   cdata.set('PG_INT64_TYPE', 'long long int')
1494   cdata.set_quoted('INT64_MODIFIER', 'll')
1495 else
1496   error('do not know how to get a 64bit int')
1497 endif
1499 if host_machine.endian() == 'big'
1500   cdata.set('WORDS_BIGENDIAN', 1)
1501 endif
1503 alignof_types = ['short', 'int', 'long', 'double']
1504 maxalign = 0
1505 foreach t : alignof_types
1506   align = cc.alignment(t, args: test_c_args)
1507   if maxalign < align
1508     maxalign = align
1509   endif
1510   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1511 endforeach
1512 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1514 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1515 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1518 # Check if __int128 is a working 128 bit integer type, and if so
1519 # define PG_INT128_TYPE to that typename.
1521 # This currently only detects a GCC/clang extension, but support for other
1522 # environments may be added in the future.
1524 # For the moment we only test for support for 128bit math; support for
1525 # 128bit literals and snprintf is not required.
1526 if cc.links('''
1527   /*
1528    * We don't actually run this test, just link it to verify that any support
1529    * functions needed for __int128 are present.
1530    *
1531    * These are globals to discourage the compiler from folding all the
1532    * arithmetic tests down to compile-time constants.  We do not have
1533    * convenient support for 128bit literals at this point...
1534    */
1535   __int128 a = 48828125;
1536   __int128 b = 97656250;
1538   int main(void)
1539   {
1540       __int128 c,d;
1541       a = (a << 12) + 1; /* 200000000001 */
1542       b = (b << 12) + 5; /* 400000000005 */
1543       /* try the most relevant arithmetic ops */
1544       c = a * b;
1545       d = (c + b) / b;
1546       /* must use the results, else compiler may optimize arithmetic away */
1547       return d != a+1;
1548   }''',
1549   name: '__int128',
1550   args: test_c_args)
1552   buggy_int128 = false
1554   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1555   # If not cross-compiling, we can test for bugs and disable use of __int128
1556   # with buggy compilers.  If cross-compiling, hope for the best.
1557   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1558   if not meson.is_cross_build()
1559     r = cc.run('''
1560     /* This must match the corresponding code in c.h: */
1561     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1562     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1563     #elif defined(_MSC_VER)
1564     #define pg_attribute_aligned(a) __declspec(align(a))
1565     #endif
1566     typedef __int128 int128a
1567     #if defined(pg_attribute_aligned)
1568     pg_attribute_aligned(8)
1569     #endif
1570     ;
1572     int128a holder;
1573     void pass_by_val(void *buffer, int128a par) { holder = par; }
1575     int main(void)
1576     {
1577         long int i64 = 97656225L << 12;
1578         int128a q;
1579         pass_by_val(main, (int128a) i64);
1580         q = (int128a) i64;
1581         return q != holder;
1582     }''',
1583     name: '__int128 alignment bug',
1584     args: test_c_args)
1585     assert(r.compiled())
1586     if r.returncode() != 0
1587       buggy_int128 = true
1588       message('__int128 support present but buggy and thus disabled')
1589     endif
1590   endif
1592   if not buggy_int128
1593     cdata.set('PG_INT128_TYPE', '__int128')
1594     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1595       alignment('__int128', args: test_c_args))
1596   endif
1597 endif
1600 # Check if the C compiler knows computed gotos (gcc extension, also
1601 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1603 # Checking whether computed gotos are supported syntax-wise ought to
1604 # be enough, as the syntax is otherwise illegal.
1605 if cc.compiles('''
1606     static inline int foo(void)
1607     {
1608       void *labeladdrs[] = {&&my_label};
1609       goto *labeladdrs[0];
1610       my_label:
1611       return 1;
1612     }''',
1613     args: test_c_args)
1614   cdata.set('HAVE_COMPUTED_GOTO', 1)
1615 endif
1618 # Check if the C compiler understands _Static_assert(),
1619 # and define HAVE__STATIC_ASSERT if so.
1621 # We actually check the syntax ({ _Static_assert(...) }), because we need
1622 # gcc-style compound expressions to be able to wrap the thing into macros.
1623 if cc.compiles('''
1624     int main(int arg, char **argv)
1625     {
1626         ({ _Static_assert(1, "foo"); });
1627     }
1628     ''',
1629     args: test_c_args)
1630   cdata.set('HAVE__STATIC_ASSERT', 1)
1631 endif
1634 # We use <stdbool.h> if we have it and it declares type bool as having
1635 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1636 if cc.has_type('_Bool', args: test_c_args) \
1637   and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1638   and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1639   cdata.set('HAVE__BOOL', 1)
1640   cdata.set('PG_USE_STDBOOL', 1)
1641 endif
1644 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1645 # warning for each use of %m.
1646 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1647 testsrc = '''
1648 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1649 static void call_log(void)
1651     emit_log(0, "error: %s: %m", "foo");
1654 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1655 foreach a : printf_attributes
1656   if cc.compiles(testsrc.format(a),
1657       args: test_c_args + attrib_error_args, name: 'format ' + a)
1658     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1659     break
1660   endif
1661 endforeach
1664 if cc.has_function_attribute('visibility:default') and \
1665   cc.has_function_attribute('visibility:hidden')
1666   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1668   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1669   # inlineshidden to C code as well... Any either way, we want to put these
1670   # flags into exported files (pgxs, .pc files).
1671   cflags_mod += '-fvisibility=hidden'
1672   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1673   ldflags_mod += '-fvisibility=hidden'
1674 endif
1677 # Check if various builtins exist. Some builtins are tested separately,
1678 # because we want to test something more complicated than the generic case.
1679 builtins = [
1680   'bswap16',
1681   'bswap32',
1682   'bswap64',
1683   'clz',
1684   'ctz',
1685   'constant_p',
1686   'frame_address',
1687   'popcount',
1688   'unreachable',
1691 foreach builtin : builtins
1692   fname = '__builtin_@0@'.format(builtin)
1693   if cc.has_function(fname, args: test_c_args)
1694     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1695   endif
1696 endforeach
1699 # Check if the C compiler understands __builtin_types_compatible_p,
1700 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1702 # We check usage with __typeof__, though it's unlikely any compiler would
1703 # have the former and not the latter.
1704 if cc.compiles('''
1705     static int x;
1706     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1707     ''',
1708     name: '__builtin_types_compatible_p',
1709     args: test_c_args)
1710   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1711 endif
1714 # Check if the C compiler understands __builtin_$op_overflow(),
1715 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1717 # Check for the most complicated case, 64 bit multiplication, as a
1718 # proxy for all of the operations.  To detect the case where the compiler
1719 # knows the function but library support is missing, we must link not just
1720 # compile, and store the results in global variables so the compiler doesn't
1721 # optimize away the call.
1722 if cc.links('''
1723     INT64 a = 1;
1724     INT64 b = 1;
1725     INT64 result;
1727     int main(void)
1728     {
1729         return __builtin_mul_overflow(a, b, &result);
1730     }''',
1731     name: '__builtin_mul_overflow',
1732     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1733     )
1734   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1735 endif
1738 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1739 # here. To prevent problems due to two detection methods working, stop
1740 # checking after one.
1741 if cc.links('''
1742     #include <cpuid.h>
1743     int main(int arg, char **argv)
1744     {
1745         unsigned int exx[4] = {0, 0, 0, 0};
1746         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1747     }
1748     ''', name: '__get_cpuid',
1749     args: test_c_args)
1750   cdata.set('HAVE__GET_CPUID', 1)
1751 elif cc.links('''
1752     #include <intrin.h>
1753     int main(int arg, char **argv)
1754     {
1755         unsigned int exx[4] = {0, 0, 0, 0};
1756         __cpuid(exx, 1);
1757     }
1758     ''', name: '__cpuid',
1759     args: test_c_args)
1760   cdata.set('HAVE__CPUID', 1)
1761 endif
1764 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1765 # versions of clang do not understand -fexcess-precision=standard, the use of
1766 # x87 floating point operations leads to problems like isinf possibly returning
1767 # false for a value that is infinite when converted from the 80bit register to
1768 # the 8byte memory representation.
1770 # Only perform the test if the compiler doesn't understand
1771 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1772 # automatically.
1773 if '-fexcess-precision=standard' not in cflags
1774   if not cc.compiles('''
1775 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1776 choke me
1777 #endif''',
1778       name: '', args: test_c_args)
1779     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1780   endif
1781 endif
1785 ###############################################################
1786 # Compiler flags
1787 ###############################################################
1789 common_functional_flags = [
1790   # Disable strict-aliasing rules; needed for gcc 3.3+
1791   '-fno-strict-aliasing',
1792   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1793   '-fwrapv',
1794   '-fexcess-precision=standard',
1797 cflags += cc.get_supported_arguments(common_functional_flags)
1798 if llvm.found()
1799   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1800 endif
1802 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1803 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1805 common_warning_flags = [
1806   '-Wmissing-prototypes',
1807   '-Wpointer-arith',
1808   # Really don't want VLAs to be used in our dialect of C
1809   '-Werror=vla',
1810   # On macOS, complain about usage of symbols newer than the deployment target
1811   '-Werror=unguarded-availability-new',
1812   '-Wendif-labels',
1813   '-Wmissing-format-attribute',
1814   '-Wimplicit-fallthrough=3',
1815   '-Wcast-function-type',
1816   '-Wshadow=compatible-local',
1817   # This was included in -Wall/-Wformat in older GCC versions
1818   '-Wformat-security',
1821 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1822 if llvm.found()
1823   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1824 endif
1826 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1827 # the result for them
1828 cflags_no_decl_after_statement = []
1829 if cc.has_argument('-Wdeclaration-after-statement')
1830   cflags_warn += '-Wdeclaration-after-statement'
1831   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1832 endif
1835 # The following tests want to suppress various unhelpful warnings by adding
1836 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1837 # switches, so we have to test for the positive form and if that works,
1838 # add the negative form.
1840 negative_warning_flags = [
1841   # Suppress clang's unhelpful unused-command-line-argument warnings.
1842   'unused-command-line-argument',
1844   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1845   # of warnings when building plperl because of usages in the Perl headers.
1846   'compound-token-split-by-macro',
1848   # Similarly disable useless truncation warnings from gcc 8+
1849   'format-truncation',
1850   'stringop-truncation',
1852   # Suppress clang 16's strict warnings about function casts
1853   'cast-function-type-strict',
1855   # To make warning_level=2 / -Wextra work, we'd need at least the following
1856   # 'clobbered',
1857   # 'missing-field-initializers',
1858   # 'sign-compare',
1859   # 'unused-parameter',
1862 foreach w : negative_warning_flags
1863   if cc.has_argument('-W' + w)
1864     cflags_warn += '-Wno-' + w
1865   endif
1866   if llvm.found() and cpp.has_argument('-W' + w)
1867     cxxflags_warn += '-Wno-' + w
1868   endif
1869 endforeach
1872 # From Project.pm
1873 if cc.get_id() == 'msvc'
1874   cflags_warn += [
1875     '/wd4018', # signed/unsigned mismatch
1876     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1877     '/wd4273', # inconsistent DLL linkage
1878     '/wd4101', # unreferenced local variable
1879     '/wd4102', # unreferenced label
1880     '/wd4090', # different 'modifier' qualifiers
1881     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1882   ]
1884   cppflags += [
1885     '/DWIN32',
1886     '/DWINDOWS',
1887     '/D__WINDOWS__',
1888     '/D__WIN32__',
1889     '/D_CRT_SECURE_NO_DEPRECATE',
1890     '/D_CRT_NONSTDC_NO_DEPRECATE',
1891   ]
1893   # We never need export libraries. As link.exe reports their creation, they
1894   # are unnecessarily noisy. Similarly, we don't need import library for
1895   # modules, we only import them dynamically, and they're also noisy.
1896   ldflags += '/NOEXP'
1897   ldflags_mod += '/NOIMPLIB'
1898 endif
1902 ###############################################################
1903 # Atomics
1904 ###############################################################
1906 if not get_option('spinlocks')
1907   warning('Not using spinlocks will cause poor performance')
1908 else
1909   cdata.set('HAVE_SPINLOCKS', 1)
1910 endif
1912 if not get_option('atomics')
1913   warning('Not using atomics will cause poor performance')
1914 else
1915   # XXX: perhaps we should require some atomics support in this case these
1916   # days?
1917   cdata.set('HAVE_ATOMICS', 1)
1919   atomic_checks = [
1920     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1921      'desc': '__sync_lock_test_and_set(char)',
1922      'test': '''
1923 char lock = 0;
1924 __sync_lock_test_and_set(&lock, 1);
1925 __sync_lock_release(&lock);'''},
1927     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1928      'desc': '__sync_lock_test_and_set(int32)',
1929      'test': '''
1930 int lock = 0;
1931 __sync_lock_test_and_set(&lock, 1);
1932 __sync_lock_release(&lock);'''},
1934     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1935      'desc': '__sync_val_compare_and_swap(int32)',
1936      'test': '''
1937 int val = 0;
1938 __sync_val_compare_and_swap(&val, 0, 37);'''},
1940     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1941      'desc': '__sync_val_compare_and_swap(int64)',
1942      'test': '''
1943 INT64 val = 0;
1944 __sync_val_compare_and_swap(&val, 0, 37);'''},
1946     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1947      'desc': ' __atomic_compare_exchange_n(int32)',
1948      'test': '''
1949 int val = 0;
1950 int expect = 0;
1951 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1953     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1954      'desc': ' __atomic_compare_exchange_n(int64)',
1955      'test': '''
1956 INT64 val = 0;
1957 INT64 expect = 0;
1958 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1959   ]
1961   foreach check : atomic_checks
1962     test = '''
1963 int main(void)
1966 }'''.format(check['test'])
1968     cdata.set(check['name'],
1969       cc.links(test,
1970         name: check['desc'],
1971         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1972     )
1973   endforeach
1975 endif
1979 ###############################################################
1980 # Select CRC-32C implementation.
1982 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1983 # use the special CRC instructions for calculating CRC-32C. If we're not
1984 # targeting such a processor, but we can nevertheless produce code that uses
1985 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1986 # implementations and select which one to use at runtime, depending on whether
1987 # SSE 4.2 is supported by the processor we're running on.
1989 # Similarly, if we are targeting an ARM processor that has the CRC
1990 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1991 # we're not targeting such a processor, but can nevertheless produce code that
1992 # uses the CRC instructions, compile both, and select at runtime.
1993 ###############################################################
1995 have_optimized_crc = false
1996 cflags_crc = []
1997 if host_cpu == 'x86' or host_cpu == 'x86_64'
1999   if cc.get_id() == 'msvc'
2000     cdata.set('USE_SSE42_CRC32C', false)
2001     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2002     have_optimized_crc = true
2003   else
2005     prog = '''
2006 #include <nmmintrin.h>
2008 int main(void)
2010     unsigned int crc = 0;
2011     crc = _mm_crc32_u8(crc, 0);
2012     crc = _mm_crc32_u32(crc, 0);
2013     /* return computed value, to prevent the above being optimized away */
2014     return crc == 0;
2018     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2019           args: test_c_args)
2020       # Use Intel SSE 4.2 unconditionally.
2021       cdata.set('USE_SSE42_CRC32C', 1)
2022       have_optimized_crc = true
2023     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2024           args: test_c_args + ['-msse4.2'])
2025       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2026       # the runtime check.
2027       cflags_crc += '-msse4.2'
2028       cdata.set('USE_SSE42_CRC32C', false)
2029       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2030       have_optimized_crc = true
2031     endif
2033   endif
2035 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2037   prog = '''
2038 #include <arm_acle.h>
2040 int main(void)
2042     unsigned int crc = 0;
2043     crc = __crc32cb(crc, 0);
2044     crc = __crc32ch(crc, 0);
2045     crc = __crc32cw(crc, 0);
2046     crc = __crc32cd(crc, 0);
2048     /* return computed value, to prevent the above being optimized away */
2049     return crc == 0;
2053   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2054       args: test_c_args)
2055     # Use ARM CRC Extension unconditionally
2056     cdata.set('USE_ARMV8_CRC32C', 1)
2057     have_optimized_crc = true
2058   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2059       args: test_c_args + ['-march=armv8-a+crc'])
2060     # Use ARM CRC Extension, with runtime check
2061     cflags_crc += '-march=armv8-a+crc'
2062     cdata.set('USE_ARMV8_CRC32C', false)
2063     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2064     have_optimized_crc = true
2065   endif
2066 endif
2068 if not have_optimized_crc
2069   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2070   # support.
2071   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2072 endif
2076 ###############################################################
2077 # Other CPU specific stuff
2078 ###############################################################
2080 if host_cpu == 'x86_64'
2082   if cc.compiles('''
2083       void main(void)
2084       {
2085           long long x = 1; long long r;
2086           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2087       }''',
2088       name: '@0@: popcntq instruction'.format(host_cpu),
2089       args: test_c_args)
2090     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2091   endif
2093 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2094   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2095   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2096     if cc.compiles('''
2097       static inline int
2098       addi(int ra, int si)
2099       {
2100           int res = 0;
2101           if (__builtin_constant_p(si))
2102               __asm__ __volatile__(
2103                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2104           return res;
2105       }
2106       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2107       ''',
2108       args: test_c_args)
2109       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2110     endif
2111   endif
2112 endif
2116 ###############################################################
2117 # Library / OS tests
2118 ###############################################################
2120 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2121 # unnecessary checks over and over, particularly on windows.
2122 header_checks = [
2123   'atomic.h',
2124   'copyfile.h',
2125   'crtdefs.h',
2126   'execinfo.h',
2127   'getopt.h',
2128   'ifaddrs.h',
2129   'langinfo.h',
2130   'mbarrier.h',
2131   'stdbool.h',
2132   'strings.h',
2133   'sys/epoll.h',
2134   'sys/event.h',
2135   'sys/personality.h',
2136   'sys/prctl.h',
2137   'sys/procctl.h',
2138   'sys/signalfd.h',
2139   'sys/ucred.h',
2140   'termios.h',
2141   'ucred.h',
2144 foreach header : header_checks
2145   varname = 'HAVE_' + header.underscorify().to_upper()
2147   # Emulate autoconf behaviour of not-found->undef, found->1
2148   found = cc.has_header(header,
2149     include_directories: postgres_inc, args: test_c_args)
2150   cdata.set(varname, found ? 1 : false,
2151             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2152 endforeach
2155 decl_checks = [
2156   ['F_FULLFSYNC', 'fcntl.h'],
2157   ['fdatasync', 'unistd.h'],
2158   ['posix_fadvise', 'fcntl.h'],
2159   ['strlcat', 'string.h'],
2160   ['strlcpy', 'string.h'],
2161   ['strnlen', 'string.h'],
2164 # Need to check for function declarations for these functions, because
2165 # checking for library symbols wouldn't handle deployment target
2166 # restrictions on macOS
2167 decl_checks += [
2168   ['preadv', 'sys/uio.h'],
2169   ['pwritev', 'sys/uio.h'],
2172 foreach c : decl_checks
2173   func = c.get(0)
2174   header = c.get(1)
2175   args = c.get(2, {})
2176   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2178   found = cc.has_header_symbol(header, func,
2179     args: test_c_args, include_directories: postgres_inc,
2180     kwargs: args)
2181   cdata.set10(varname, found, description:
2182 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2183    don't.'''.format(func))
2184 endforeach
2187 if cc.has_type('struct option',
2188     args: test_c_args, include_directories: postgres_inc,
2189     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2190   cdata.set('HAVE_STRUCT_OPTION', 1)
2191 endif
2194 foreach c : ['opterr', 'optreset']
2195   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2197   if cc.links('''
2198 #include <unistd.h>
2199 int main(void)
2201     extern int @0@;
2202     @0@ = 1;
2204 '''.format(c), name: c, args: test_c_args)
2205     cdata.set(varname, 1)
2206   else
2207     cdata.set(varname, false)
2208   endif
2209 endforeach
2211 if cc.has_type('socklen_t',
2212     args: test_c_args, include_directories: postgres_inc,
2213     prefix: '''
2214 #include <sys/socket.h>''')
2215   cdata.set('HAVE_SOCKLEN_T', 1)
2216 endif
2218 if cc.has_member('struct sockaddr', 'sa_len',
2219     args: test_c_args, include_directories: postgres_inc,
2220     prefix: '''
2221 #include <sys/types.h>
2222 #include <sys/socket.h>''')
2223   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2224 endif
2226 if cc.has_member('struct tm', 'tm_zone',
2227     args: test_c_args, include_directories: postgres_inc,
2228     prefix: '''
2229 #include <sys/types.h>
2230 #include <time.h>
2231 ''')
2232   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2233 endif
2235 if cc.compiles('''
2236 #include <time.h>
2237 extern int foo(void);
2238 int foo(void)
2240     return timezone / 60;
2242 ''',
2243     name: 'global variable `timezone\' exists',
2244     args: test_c_args, include_directories: postgres_inc)
2245   cdata.set('HAVE_INT_TIMEZONE', 1)
2246 else
2247   cdata.set('HAVE_INT_TIMEZONE', false)
2248 endif
2250 if cc.has_type('union semun',
2251     args: test_c_args,
2252     include_directories: postgres_inc,
2253     prefix: '''
2254 #include <sys/types.h>
2255 #include <sys/ipc.h>
2256 #include <sys/sem.h>
2257 ''')
2258   cdata.set('HAVE_UNION_SEMUN', 1)
2259 endif
2261 if cc.compiles('''
2262 #include <string.h>
2263 int main(void)
2265   char buf[100];
2266   switch (strerror_r(1, buf, sizeof(buf)))
2267   { case 0: break; default: break; }
2268 }''',
2269     name: 'strerror_r',
2270     args: test_c_args, include_directories: postgres_inc)
2271   cdata.set('STRERROR_R_INT', 1)
2272 else
2273   cdata.set('STRERROR_R_INT', false)
2274 endif
2276 # Check for the locale_t type and find the right header file.  macOS
2277 # needs xlocale.h; standard is locale.h, but glibc also has an
2278 # xlocale.h file that we should not use.  MSVC has a replacement
2279 # defined in src/include/port/win32_port.h.
2280 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2281   cdata.set('HAVE_LOCALE_T', 1)
2282 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2283   cdata.set('HAVE_LOCALE_T', 1)
2284   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2285 elif cc.get_id() == 'msvc'
2286   cdata.set('HAVE_LOCALE_T', 1)
2287 endif
2289 # Check if the C compiler understands typeof or a variant.  Define
2290 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2291 foreach kw : ['typeof', '__typeof__', 'decltype']
2292   if cc.compiles('''
2293 int main(void)
2295     int x = 0;
2296     @0@(x) y;
2297     y = x;
2298     return y;
2300 '''.format(kw),
2301     name: 'typeof()',
2302     args: test_c_args, include_directories: postgres_inc)
2304     cdata.set('HAVE_TYPEOF', 1)
2305     if kw != 'typeof'
2306       cdata.set('typeof', kw)
2307     endif
2309     break
2310   endif
2311 endforeach
2314 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2315 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2316 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2317 wcstombs_l_test = '''
2318 #include <stdlib.h>
2319 #include <locale.h>
2322 void main(void)
2324 #ifndef wcstombs_l
2325     (void) wcstombs_l;
2326 #endif
2329 if (not cc.compiles(wcstombs_l_test.format(''),
2330       name: 'wcstombs_l') and
2331     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2332       name: 'wcstombs_l in xlocale.h'))
2333     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2334 endif
2337 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2338 # understands, because it conflicts with __declspec(restrict). Therefore we
2339 # define pg_restrict to the appropriate definition, which presumably won't
2340 # conflict.
2342 # We assume C99 support, so we don't need to make this conditional.
2344 # XXX: Historically we allowed platforms to disable restrict in template
2345 # files, but that was only added for AIX when building with XLC, which we
2346 # don't support yet.
2347 cdata.set('pg_restrict', '__restrict')
2350 # Most libraries are included only if they demonstrably provide a function we
2351 # need, but libm is an exception: always include it, because there are too
2352 # many compilers that play cute optimization games that will break probes for
2353 # standard functions such as pow().
2354 os_deps += cc.find_library('m', required: false)
2356 rt_dep = cc.find_library('rt', required: false)
2358 dl_dep = cc.find_library('dl', required: false)
2360 util_dep = cc.find_library('util', required: false)
2361 posix4_dep = cc.find_library('posix4', required: false)
2363 getopt_dep = cc.find_library('getopt', required: false)
2364 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2365 # Check if we want to replace getopt/getopt_long even if provided by the system
2366 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2367 #   so always use our version on Windows
2368 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2369 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2370 # - We want to use system's getopt_long() only if the system provides struct
2371 #   option
2372 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2373 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2375 # Required on BSDs
2376 execinfo_dep = cc.find_library('execinfo', required: false)
2378 if host_system == 'cygwin'
2379   cygipc_dep = cc.find_library('cygipc', required: false)
2380 else
2381   cygipc_dep = not_found_dep
2382 endif
2384 if host_system == 'sunos'
2385   socket_dep = cc.find_library('socket', required: false)
2386 else
2387   socket_dep = not_found_dep
2388 endif
2390 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2391 # unnecessary checks over and over, particularly on windows.
2392 func_checks = [
2393   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2394   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2395   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2396   ['copyfile'],
2397   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2398   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2399   # required. Just checking for dlsym() ought to suffice.
2400   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2401   ['explicit_bzero'],
2402   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2403   ['getifaddrs'],
2404   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2405   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2406   ['getpeereid'],
2407   ['getpeerucred'],
2408   ['inet_aton'],
2409   ['inet_pton'],
2410   ['kqueue'],
2411   ['mbstowcs_l'],
2412   ['memset_s'],
2413   ['mkdtemp'],
2414   ['posix_fadvise'],
2415   ['posix_fallocate'],
2416   ['ppoll'],
2417   ['pstat'],
2418   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2419   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2420   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2421   ['setproctitle', {'dependencies': [util_dep]}],
2422   ['setproctitle_fast'],
2423   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2424   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2425   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2426   ['socket', {'dependencies': [socket_dep], 'define': false}],
2427   ['strchrnul'],
2428   ['strerror_r', {'dependencies': [thread_dep]}],
2429   ['strlcat'],
2430   ['strlcpy'],
2431   ['strnlen'],
2432   ['strsignal'],
2433   ['sync_file_range'],
2434   ['syncfs'],
2435   ['uselocale'],
2436   ['wcstombs_l'],
2439 func_check_results = {}
2440 foreach c : func_checks
2441   func = c.get(0)
2442   kwargs = c.get(1, {})
2443   deps = kwargs.get('dependencies', [])
2445   if kwargs.get('skip', false)
2446     continue
2447   endif
2449   found = cc.has_function(func, args: test_c_args)
2451   if not found
2452     foreach dep : deps
2453       if not dep.found()
2454         continue
2455       endif
2456       found = cc.has_function(func, args: test_c_args,
2457                               dependencies: [dep])
2458       if found
2459         os_deps += dep
2460         break
2461       endif
2462     endforeach
2463   endif
2465   func_check_results += {func: found}
2467   if kwargs.get('define', true)
2468     # Emulate autoconf behaviour of not-found->undef, found->1
2469     cdata.set('HAVE_' + func.underscorify().to_upper(),
2470               found  ? 1 : false,
2471               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2472   endif
2473 endforeach
2476 if cc.has_function('syslog', args: test_c_args) and \
2477     cc.check_header('syslog.h', args: test_c_args)
2478   cdata.set('HAVE_SYSLOG', 1)
2479 endif
2482 # MSVC has replacements defined in src/include/port/win32_port.h.
2483 if cc.get_id() == 'msvc'
2484   cdata.set('HAVE_WCSTOMBS_L', 1)
2485   cdata.set('HAVE_MBSTOWCS_L', 1)
2486 endif
2489 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2490 # semaphores
2491 if sema_kind == 'unnamed_posix' and \
2492    not func_check_results.get('sem_init', false)
2493   sema_kind = 'sysv'
2494 endif
2496 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2497 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2499 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2500 cdata.set_quoted('DLSUFFIX', dlsuffix)
2503 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2504 cdata.set_quoted('PG_VERSION_STR',
2505   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2506     pg_version, host_machine.cpu_family(), host_system,
2507     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2508   )
2513 ###############################################################
2514 # Threading
2515 ###############################################################
2517 # XXX: About to rely on thread safety in the autoconf build, so not worth
2518 # implementing a fallback.
2519 cdata.set('ENABLE_THREAD_SAFETY', 1)
2523 ###############################################################
2524 # NLS / Gettext
2525 ###############################################################
2527 nlsopt = get_option('nls')
2528 libintl = not_found_dep
2530 if not nlsopt.disabled()
2531   # otherwise there'd be lots of
2532   # "Gettext not found, all translation (po) targets will be ignored."
2533   # warnings if not found.
2534   msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2536   # meson 0.59 has this wrapped in dependency('int')
2537   if (msgfmt.found() and
2538       cc.check_header('libintl.h', required: nlsopt,
2539         args: test_c_args, include_directories: postgres_inc))
2541     # in libc
2542     if cc.has_function('ngettext')
2543       libintl = declare_dependency()
2544     else
2545       libintl = cc.find_library('intl',
2546         has_headers: ['libintl.h'], required: nlsopt,
2547         header_include_directories: postgres_inc,
2548         dirs: test_lib_d)
2549     endif
2550   endif
2552   if libintl.found()
2553     i18n = import('i18n')
2554     cdata.set('ENABLE_NLS', 1)
2555   endif
2556 endif
2560 ###############################################################
2561 # Build
2562 ###############################################################
2564 # Set up compiler / linker arguments to be used everywhere, individual targets
2565 # can add further args directly, or indirectly via dependencies
2566 add_project_arguments(cflags, language: ['c'])
2567 add_project_arguments(cppflags, language: ['c'])
2568 add_project_arguments(cflags_warn, language: ['c'])
2569 add_project_arguments(cxxflags, language: ['cpp'])
2570 add_project_arguments(cppflags, language: ['cpp'])
2571 add_project_arguments(cxxflags_warn, language: ['cpp'])
2572 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2575 # Collect a number of lists of things while recursing through the source
2576 # tree. Later steps then can use those.
2578 # list of targets for various alias targets
2579 backend_targets = []
2580 bin_targets = []
2581 pl_targets = []
2582 contrib_targets = []
2583 testprep_targets = []
2584 nls_targets = []
2587 # Define the tests to distribute them to the correct test styles later
2588 test_deps = []
2589 tests = []
2592 # Default options for targets
2594 # First identify rpaths
2595 bin_install_rpaths = []
2596 lib_install_rpaths = []
2597 mod_install_rpaths = []
2600 # Don't add rpaths on darwin for now - as long as only absolute references to
2601 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2602 # their final destination.
2603 if host_system != 'darwin'
2604   # Add absolute path to libdir to rpath. This ensures installed binaries /
2605   # libraries find our libraries (mainly libpq).
2606   bin_install_rpaths += dir_prefix / dir_lib
2607   lib_install_rpaths += dir_prefix / dir_lib
2608   mod_install_rpaths += dir_prefix / dir_lib
2610   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2611   #
2612   # Not needed on darwin even if we use relative rpaths for our own libraries,
2613   # as the install_name of libraries in extra_lib_dirs will point to their
2614   # location anyway.
2615   bin_install_rpaths += postgres_lib_d
2616   lib_install_rpaths += postgres_lib_d
2617   mod_install_rpaths += postgres_lib_d
2618 endif
2621 # Define arguments for default targets
2623 default_target_args = {
2624   'implicit_include_directories': false,
2625   'install': true,
2628 default_lib_args = default_target_args + {
2629   'name_prefix': '',
2632 internal_lib_args = default_lib_args + {
2633   'build_by_default': false,
2634   'install': false,
2637 default_mod_args = default_lib_args + {
2638   'name_prefix': '',
2639   'install_dir': dir_lib_pkg,
2642 default_bin_args = default_target_args + {
2643   'install_dir': dir_bin,
2646 if get_option('rpath')
2647   default_lib_args += {
2648     'install_rpath': ':'.join(lib_install_rpaths),
2649   }
2651   default_mod_args += {
2652     'install_rpath': ':'.join(mod_install_rpaths),
2653   }
2655   default_bin_args += {
2656     'install_rpath': ':'.join(bin_install_rpaths),
2657   }
2658 endif
2661 # Helper for exporting a limited number of symbols
2662 gen_export_kwargs = {
2663   'input': 'exports.txt',
2664   'output': '@BASENAME@.'+export_file_suffix,
2665   'command': [perl, files('src/tools/gen_export.pl'),
2666    '--format', export_file_format,
2667    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2668   'build_by_default': false,
2669   'install': false,
2675 ### windows resources related stuff
2678 if host_system == 'windows'
2679   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2680   win32ver_rc = files('src/port/win32ver.rc')
2681   rcgen = find_program('src/tools/rcgen', native: true)
2683   rcgen_base_args = [
2684     '--srcdir', '@SOURCE_DIR@',
2685     '--builddir', meson.build_root(),
2686     '--rcout', '@OUTPUT0@',
2687     '--out', '@OUTPUT1@',
2688     '--input', '@INPUT@',
2689     '@EXTRA_ARGS@',
2690   ]
2692   if cc.get_argument_syntax() == 'msvc'
2693     rc = find_program('rc', required: true)
2694     rcgen_base_args += ['--rc', rc.path()]
2695     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2696   else
2697     windres = find_program('windres', required: true)
2698     rcgen_base_args += ['--windres', windres.path()]
2699     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2700   endif
2702   # msbuild backend doesn't support this atm
2703   if meson.backend() == 'ninja'
2704     rcgen_base_args += ['--depfile', '@DEPFILE@']
2705   endif
2707   rcgen_bin_args = rcgen_base_args + [
2708     '--VFT_TYPE', 'VFT_APP',
2709     '--FILEENDING', 'exe',
2710     '--ICO', pg_ico
2711   ]
2713   rcgen_lib_args = rcgen_base_args + [
2714     '--VFT_TYPE', 'VFT_DLL',
2715     '--FILEENDING', 'dll',
2716   ]
2718   rc_bin_gen = generator(rcgen,
2719     depfile: '@BASENAME@.d',
2720     arguments: rcgen_bin_args,
2721     output: rcgen_outputs,
2722   )
2724   rc_lib_gen = generator(rcgen,
2725     depfile: '@BASENAME@.d',
2726     arguments: rcgen_lib_args,
2727     output: rcgen_outputs,
2728   )
2729 endif
2733 # headers that the whole build tree depends on
2734 generated_headers = []
2735 # headers that the backend build depends on
2736 generated_backend_headers = []
2737 # configure_files() output, needs a way of converting to file names
2738 configure_files = []
2740 # generated files that might conflict with a partial in-tree autoconf build
2741 generated_sources = []
2742 # same, for paths that differ between autoconf / meson builds
2743 # elements are [dir, [files]]
2744 generated_sources_ac = {}
2747 # First visit src/include - all targets creating headers are defined
2748 # within. That makes it easy to add the necessary dependencies for the
2749 # subsequent build steps.
2751 subdir('src/include')
2753 subdir('config')
2755 # Then through src/port and src/common, as most other things depend on them
2757 frontend_port_code = declare_dependency(
2758   compile_args: ['-DFRONTEND'],
2759   include_directories: [postgres_inc],
2760   dependencies: os_deps,
2763 backend_port_code = declare_dependency(
2764   compile_args: ['-DBUILDING_DLL'],
2765   include_directories: [postgres_inc],
2766   sources: [errcodes], # errcodes.h is needed due to use of ereport
2767   dependencies: os_deps,
2770 subdir('src/port')
2772 frontend_common_code = declare_dependency(
2773   compile_args: ['-DFRONTEND'],
2774   include_directories: [postgres_inc],
2775   sources: generated_headers,
2776   dependencies: [os_deps, zlib, zstd],
2779 backend_common_code = declare_dependency(
2780   compile_args: ['-DBUILDING_DLL'],
2781   include_directories: [postgres_inc],
2782   sources: generated_headers,
2783   dependencies: [os_deps, zlib, zstd],
2786 subdir('src/common')
2788 # all shared libraries should depend on shlib_code
2789 shlib_code = declare_dependency(
2790   link_args: ldflags_sl,
2793 # all static libraries not part of the backend should depend on this
2794 frontend_stlib_code = declare_dependency(
2795   include_directories: [postgres_inc],
2796   link_with: [common_static, pgport_static],
2797   sources: generated_headers,
2798   dependencies: [os_deps, libintl],
2801 # all shared libraries not part of the backend should depend on this
2802 frontend_shlib_code = declare_dependency(
2803   include_directories: [postgres_inc],
2804   link_with: [common_shlib, pgport_shlib],
2805   sources: generated_headers,
2806   dependencies: [shlib_code, os_deps, libintl],
2809 # Dependencies both for static and shared libpq
2810 libpq_deps += [
2811   thread_dep,
2813   gssapi,
2814   ldap_r,
2815   libintl,
2816   ssl,
2819 subdir('src/interfaces/libpq')
2820 # fe_utils depends on libpq
2821 subdir('src/fe_utils')
2823 # for frontend binaries
2824 frontend_code = declare_dependency(
2825   include_directories: [postgres_inc],
2826   link_with: [fe_utils, common_static, pgport_static],
2827   sources: generated_headers,
2828   dependencies: [os_deps, libintl],
2831 backend_both_deps += [
2832   thread_dep,
2833   bsd_auth,
2834   gssapi,
2835   icu,
2836   icu_i18n,
2837   ldap,
2838   libintl,
2839   libxml,
2840   lz4,
2841   pam,
2842   ssl,
2843   systemd,
2844   zlib,
2845   zstd,
2848 backend_mod_deps = backend_both_deps + os_deps
2850 backend_code = declare_dependency(
2851   compile_args: ['-DBUILDING_DLL'],
2852   include_directories: [postgres_inc],
2853   link_args: ldflags_be,
2854   link_with: [],
2855   sources: generated_headers + generated_backend_headers,
2856   dependencies: os_deps + backend_both_deps + backend_deps,
2859 # install these files only during test, not main install
2860 test_install_data = []
2861 test_install_libs = []
2863 # src/backend/meson.build defines backend_mod_code used for extension
2864 # libraries.
2867 # Then through the main sources. That way contrib can have dependencies on
2868 # main sources. Note that this explicitly doesn't enter src/test, right now a
2869 # few regression tests depend on contrib files.
2871 subdir('src')
2873 subdir('contrib')
2875 subdir('src/test')
2876 subdir('src/interfaces/libpq/test')
2877 subdir('src/interfaces/ecpg/test')
2879 subdir('doc/src/sgml')
2881 generated_sources_ac += {'': ['GNUmakefile']}
2883 # After processing src/test, add test_install_libs to the testprep_targets
2884 # to build them
2885 testprep_targets += test_install_libs
2888 # If there are any files in the source directory that we also generate in the
2889 # build directory, they might get preferred over the newly generated files,
2890 # e.g. because of a #include "file", which always will search in the current
2891 # directory first.
2892 message('checking for file conflicts between source and build directory')
2893 conflicting_files = []
2894 potentially_conflicting_files_t = []
2895 potentially_conflicting_files_t += generated_headers
2896 potentially_conflicting_files_t += generated_backend_headers
2897 potentially_conflicting_files_t += generated_backend_sources
2898 potentially_conflicting_files_t += generated_sources
2900 potentially_conflicting_files = []
2902 # convert all sources of potentially conflicting files into uniform shape
2903 foreach t : potentially_conflicting_files_t
2904   potentially_conflicting_files += t.full_path()
2905 endforeach
2906 foreach t : configure_files
2907   t = '@0@'.format(t)
2908   potentially_conflicting_files += meson.current_build_dir() / t
2909 endforeach
2910 foreach sub, fnames : generated_sources_ac
2911   sub = meson.build_root() / sub
2912   foreach fname : fnames
2913     potentially_conflicting_files += sub / fname
2914   endforeach
2915 endforeach
2917 # find and report conflicting files
2918 foreach build_path : potentially_conflicting_files
2919   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2920   # str.replace is in 0.56
2921   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2922   if fs.exists(src_path) or fs.is_symlink(src_path)
2923     conflicting_files += src_path
2924   endif
2925 endforeach
2926 # XXX: Perhaps we should generate a file that would clean these up? The list
2927 # can be long.
2928 if conflicting_files.length() > 0
2929   errmsg_cleanup = '''
2930 Conflicting files in source directory:
2931   @0@
2933 The conflicting files need to be removed, either by removing the files listed
2934 above, or by running configure and then make maintainer-clean.
2936   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2937   error(errmsg_nonclean_base.format(errmsg_cleanup))
2938 endif
2942 ###############################################################
2943 # Install targets
2944 ###############################################################
2947 # We want to define additional install targets beyond what meson provides. For
2948 # that we need to define targets depending on nearly everything. We collected
2949 # the results of i18n.gettext() invocations into nls_targets, that also
2950 # includes maintainer targets though. Collect the ones we want as a dependency.
2952 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
2953 # generation happens during install, so that's not a real issue.
2954 nls_mo_targets = []
2955 if libintl.found() and meson.version().version_compare('>=0.60')
2956   # use range() to avoid the flattening of the list that forech() would do
2957   foreach off : range(0, nls_targets.length())
2958     # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
2959     # -pot target 3) maintainer -pot target
2960     nls_mo_targets += nls_targets[off][0]
2961   endforeach
2962   alias_target('nls', nls_mo_targets)
2963 endif
2966 all_built = [
2967   backend_targets,
2968   bin_targets,
2969   libpq_st,
2970   pl_targets,
2971   contrib_targets,
2972   nls_mo_targets,
2973   testprep_targets,
2974   ecpg_targets,
2977 # Meson's default install target is quite verbose. Provide one that is quiet.
2978 install_quiet = custom_target('install-quiet',
2979   output: 'install-quiet',
2980   build_always_stale: true,
2981   build_by_default: false,
2982   command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
2983   depends: all_built,
2986 # Target to install files used for tests, which aren't installed by default
2987 install_test_files_args = [
2988   install_files,
2989   '--prefix', dir_prefix,
2990   '--install', contrib_data_dir, test_install_data,
2991   '--install', dir_lib_pkg, test_install_libs,
2993 run_target('install-test-files',
2994   command: [python] + install_test_files_args,
2995   depends: testprep_targets,
3000 ###############################################################
3001 # Test prep
3002 ###############################################################
3004 # DESTDIR for the installation we'll run tests in
3005 test_install_destdir = meson.build_root() / 'tmp_install/'
3007 # DESTDIR + prefix appropriately munged
3008 if build_system != 'windows'
3009   # On unixoid systems this is trivial, we just prepend the destdir
3010   assert(dir_prefix.startswith('/')) # enforced by meson
3011   test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3012 else
3013   # drives, drive-relative paths, etc make this complicated on windows, call
3014   # into a copy of meson's logic for it
3015   command = [
3016     python, '-c',
3017     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3018     test_install_destdir, dir_prefix]
3019   test_install_location = run_command(command, check: true).stdout().strip()
3020 endif
3022 meson_install_args = meson_args + ['install'] + {
3023     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3024     'muon': []
3025 }[meson_impl]
3027 # setup tests should  be run first,
3028 # so define priority for these
3029 setup_tests_priority = 100
3030 test('tmp_install',
3031     meson_bin, args: meson_install_args ,
3032     env: {'DESTDIR':test_install_destdir},
3033     priority: setup_tests_priority,
3034     timeout: 300,
3035     is_parallel: false,
3036     suite: ['setup'])
3038 test('install_test_files',
3039     python,
3040     args: install_test_files_args + ['--destdir', test_install_destdir],
3041     priority: setup_tests_priority,
3042     is_parallel: false,
3043     suite: ['setup'])
3045 test_result_dir = meson.build_root() / 'testrun'
3048 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3049 # inevitable conflicts from running tests in parallel, hackishly assign
3050 # different ports for different tests.
3052 testport = 40000
3054 test_env = environment()
3056 temp_install_bindir = test_install_location / get_option('bindir')
3057 test_env.set('PG_REGRESS', pg_regress.full_path())
3058 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3060 # Test suites that are not safe by default but can be run if selected
3061 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3062 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3063 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3065 # Add the temporary installation to the library search path on platforms where
3066 # that works (everything but windows, basically). On windows everything
3067 # library-like gets installed into bindir, solving that issue.
3068 if library_path_var != ''
3069   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3070 endif
3074 ###############################################################
3075 # Test Generation
3076 ###############################################################
3078 # When using a meson version understanding exclude_suites, define a
3079 # 'tmp_install' test setup (the default) that excludes tests running against a
3080 # pre-existing install and a 'running' setup that conflicts with creation of
3081 # the temporary installation and tap tests (which don't support running
3082 # against a running server).
3084 running_suites = []
3085 install_suites = []
3086 if meson.version().version_compare('>=0.57')
3087   runningcheck = true
3088 else
3089   runningcheck = false
3090 endif
3092 testwrap = files('src/tools/testwrap')
3094 foreach test_dir : tests
3095   testwrap_base = [
3096     testwrap,
3097     '--basedir', meson.build_root(),
3098     '--srcdir', test_dir['sd'],
3099   ]
3101   foreach kind, v : test_dir
3102     if kind in ['sd', 'bd', 'name']
3103       continue
3104     endif
3106     t = test_dir[kind]
3108     if kind in ['regress', 'isolation', 'ecpg']
3109       if kind == 'regress'
3110         runner = pg_regress
3111         fallback_dbname = 'regression_@0@'
3112       elif kind == 'isolation'
3113         runner = pg_isolation_regress
3114         fallback_dbname = 'isolation_regression_@0@'
3115       elif kind == 'ecpg'
3116         runner = pg_regress_ecpg
3117         fallback_dbname = 'ecpg_regression_@0@'
3118       endif
3120       test_group = test_dir['name']
3121       test_group_running = test_dir['name'] + '-running'
3123       test_output = test_result_dir / test_group / kind
3124       test_output_running = test_result_dir / test_group_running/ kind
3126       # Unless specified by the test, choose a non-conflicting database name,
3127       # to avoid conflicts when running against existing server.
3128       dbname = t.get('dbname',
3129         fallback_dbname.format(test_dir['name']))
3131       test_command_base = [
3132         runner.full_path(),
3133         '--inputdir', t.get('inputdir', test_dir['sd']),
3134         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3135         '--bindir', '',
3136         '--dlpath', test_dir['bd'],
3137         '--max-concurrent-tests=20',
3138         '--dbname', dbname,
3139       ] + t.get('regress_args', [])
3141       test_selection = []
3142       if t.has_key('schedule')
3143         test_selection += ['--schedule', t['schedule'],]
3144       endif
3146       if kind == 'isolation'
3147         test_selection += t.get('specs', [])
3148       else
3149         test_selection += t.get('sql', [])
3150       endif
3152       env = test_env
3153       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3155       test_kwargs = {
3156         'protocol': 'tap',
3157         'priority': 10,
3158         'timeout': 1000,
3159         'depends': test_deps + t.get('deps', []),
3160         'env': env,
3161       } + t.get('test_kwargs', {})
3163       test(test_group / kind,
3164         python,
3165         args: [
3166           testwrap_base,
3167           '--testgroup', test_group,
3168           '--testname', kind,
3169           '--',
3170           test_command_base,
3171           '--outputdir', test_output,
3172           '--temp-instance', test_output / 'tmp_check',
3173           '--port', testport.to_string(),
3174           test_selection,
3175         ],
3176         suite: test_group,
3177         kwargs: test_kwargs,
3178       )
3179       install_suites += test_group
3181       # some tests can't support running against running DB
3182       if runningcheck and t.get('runningcheck', true)
3183         test(test_group_running / kind,
3184           python,
3185           args: [
3186             testwrap_base,
3187             '--testgroup', test_group_running,
3188             '--testname', kind,
3189             '--',
3190             test_command_base,
3191             '--outputdir', test_output_running,
3192             test_selection,
3193           ],
3194           is_parallel: t.get('runningcheck-parallel', true),
3195           suite: test_group_running,
3196           kwargs: test_kwargs,
3197         )
3198         running_suites += test_group_running
3199       endif
3201       testport += 1
3202     elif kind == 'tap'
3203       if not tap_tests_enabled
3204         continue
3205       endif
3207       test_command = [
3208         perl.path(),
3209         '-I', meson.source_root() / 'src/test/perl',
3210         '-I', test_dir['sd'],
3211       ]
3213       # Add temporary install, the build directory for non-installed binaries and
3214       # also test/ for non-installed test binaries built separately.
3215       env = test_env
3216       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3218       foreach name, value : t.get('env', {})
3219         env.set(name, value)
3220       endforeach
3222       test_group = test_dir['name']
3223       test_kwargs = {
3224         'protocol': 'tap',
3225         'suite': test_group,
3226         'timeout': 1000,
3227         'depends': test_deps + t.get('deps', []),
3228         'env': env,
3229       } + t.get('test_kwargs', {})
3231       foreach onetap : t['tests']
3232         # Make tap test names prettier, remove t/ and .pl
3233         onetap_p = onetap
3234         if onetap_p.startswith('t/')
3235           onetap_p = onetap.split('t/')[1]
3236         endif
3237         if onetap_p.endswith('.pl')
3238           onetap_p = fs.stem(onetap_p)
3239         endif
3241         test(test_dir['name'] / onetap_p,
3242           python,
3243           kwargs: test_kwargs,
3244           args: testwrap_base + [
3245             '--testgroup', test_dir['name'],
3246             '--testname', onetap_p,
3247             '--', test_command,
3248             test_dir['sd'] / onetap,
3249           ],
3250         )
3251       endforeach
3252       install_suites += test_group
3253     else
3254       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3255     endif
3257   endforeach # kinds of tests
3259 endforeach # directories with tests
3261 # repeat condition so meson realizes version dependency
3262 if meson.version().version_compare('>=0.57')
3263   add_test_setup('tmp_install',
3264     is_default: true,
3265     exclude_suites: running_suites)
3266   add_test_setup('running',
3267     exclude_suites: ['setup'] + install_suites)
3268 endif
3272 ###############################################################
3273 # Pseudo targets
3274 ###############################################################
3276 alias_target('backend', backend_targets)
3277 alias_target('bin', bin_targets + [libpq_st])
3278 alias_target('pl', pl_targets)
3279 alias_target('contrib', contrib_targets)
3280 alias_target('testprep', testprep_targets)
3281 alias_target('install-world', install_quiet, installdocs)
3285 ###############################################################
3286 # The End, The End, My Friend
3287 ###############################################################
3289 if meson.version().version_compare('>=0.57')
3291   summary(
3292     {
3293       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3294       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3295       'segment size': get_option('segsize_blocks') != 0 ?
3296         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3297         '@0@ GB'.format(get_option('segsize')),
3298     },
3299     section: 'Data layout',
3300   )
3302   summary(
3303     {
3304       'host system': '@0@ @1@'.format(host_system, host_cpu),
3305       'build system': '@0@ @1@'.format(build_machine.system(),
3306                                        build_machine.cpu_family()),
3307     },
3308     section: 'System',
3309   )
3311   summary(
3312     {
3313       'linker': '@0@'.format(cc.get_linker_id()),
3314       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3315     },
3316     section: 'Compiler',
3317   )
3319   summary(
3320     {
3321       'CPP FLAGS': ' '.join(cppflags),
3322       'C FLAGS, functional': ' '.join(cflags),
3323       'C FLAGS, warnings': ' '.join(cflags_warn),
3324       'C FLAGS, modules': ' '.join(cflags_mod),
3325       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3326       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3327     },
3328     section: 'Compiler Flags',
3329   )
3331   if llvm.found()
3332     summary(
3333       {
3334         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3335       },
3336       section: 'Compiler',
3337     )
3339     summary(
3340       {
3341         'C++ FLAGS, functional': ' '.join(cxxflags),
3342         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3343         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3344       },
3345       section: 'Compiler Flags',
3346     )
3347   endif
3349   summary(
3350     {
3351       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3352       'dtrace': dtrace,
3353     },
3354     section: 'Programs',
3355   )
3357   summary(
3358     {
3359       'bonjour': bonjour,
3360       'bsd_auth': bsd_auth,
3361       'docs': docs_dep,
3362       'docs_pdf': docs_pdf_dep,
3363       'gss': gssapi,
3364       'icu': icu,
3365       'ldap': ldap,
3366       'libxml': libxml,
3367       'libxslt': libxslt,
3368       'llvm': llvm,
3369       'lz4': lz4,
3370       'nls': libintl,
3371       'openssl': ssl,
3372       'pam': pam,
3373       'plperl': perl_dep,
3374       'plpython': python3_dep,
3375       'pltcl': tcl_dep,
3376       'readline': readline,
3377       'selinux': selinux,
3378       'systemd': systemd,
3379       'uuid': uuid,
3380       'zlib': zlib,
3381       'zstd': zstd,
3382     },
3383     section: 'External libraries',
3384   )
3386 endif