Fix psql's behavior with \g for a multiple-command string.
[pgsql.git] / meson.build
blob253994931e8a1a4cf38dd89292d1b699a78f60f0
1 # Entry point for building PostgreSQL with meson
3 # Good starting points for writing meson.build files are:
4 #  - https://mesonbuild.com/Syntax.html
5 #  - https://mesonbuild.com/Reference-manual.html
7 project('postgresql',
8   ['c'],
9   version: '16devel',
10   license: 'PostgreSQL',
12   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
13   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
14   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
15   meson_version: '>=0.54',
16   default_options: [
17     'warning_level=1', #-Wall equivalent
18     'buildtype=release',
19     # For compatibility with the autoconf build, set a default prefix. This
20     # works even on windows, where it's a drive-relative path (i.e. when on
21     # d:/sompath it'll install to d:/usr/local/pgsql)
22     'prefix=/usr/local/pgsql',
23   ]
28 ###############################################################
29 # Basic prep
30 ###############################################################
32 fs = import('fs')
33 pkgconfig = import('pkgconfig')
35 host_system = host_machine.system()
36 build_system = build_machine.system()
37 host_cpu = host_machine.cpu_family()
39 cc = meson.get_compiler('c')
41 not_found_dep = dependency('', required: false)
42 thread_dep = dependency('threads')
46 ###############################################################
47 # Safety first
48 ###############################################################
50 # It's very easy to get into confusing states when the source directory
51 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
52 # refuse to build in that case.
54 # There's a more elaborate check later, that checks for conflicts around all
55 # generated files. But we can only do that much further down the line, so this
56 # quick check seems worth it. Adhering to this advice should clean up the
57 # conflict, but won't protect against somebody doing make distclean or just
58 # removing pg_config.h
59 errmsg_nonclean_base = '''
60 ****
61 Non-clean source code directory detected.
63 To build with meson the source tree may not have an in-place, ./configure
64 style, build configured. You can have both meson and ./configure style builds
65 for the same source tree by building out-of-source / VPATH with
66 configure. Alternatively use a separate check out for meson based builds.
68 @0@
69 ****'''
70 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
71   errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
72   error(errmsg_nonclean_base.format(errmsg_cleanup))
73 endif
77 ###############################################################
78 # Variables to be determined
79 ###############################################################
81 postgres_inc_d = ['src/include']
82 postgres_inc_d += get_option('extra_include_dirs')
84 postgres_lib_d = get_option('extra_lib_dirs')
86 cppflags = []
88 cflags = []
89 cxxflags = []
90 cflags_warn = []
91 cxxflags_warn = []
92 cflags_mod = []
93 cxxflags_mod = []
95 ldflags = []
96 ldflags_be = []
97 ldflags_sl = []
98 ldflags_mod = []
100 test_c_args = []
102 os_deps = []
103 backend_both_deps = []
104 backend_deps = []
105 libpq_deps = []
107 pg_sysroot = ''
109 # source of data for pg_config.h etc
110 cdata = configuration_data()
114 ###############################################################
115 # Version and other metadata
116 ###############################################################
118 pg_version = meson.project_version()
120 if pg_version.endswith('devel')
121   pg_version_arr = [pg_version.split('devel')[0], '0']
122 elif pg_version.contains('beta')
123   pg_version_arr = [pg_version.split('beta')[0], '0']
124 elif pg_version.contains('rc')
125   pg_version_arr = [pg_version.split('rc')[0], '0']
126 else
127   pg_version_arr = pg_version.split('.')
128 endif
130 pg_version_major = pg_version_arr[0].to_int()
131 pg_version_minor = pg_version_arr[1].to_int()
132 pg_version_num = (pg_version_major * 10000) + pg_version_minor
134 pg_url = 'https://www.postgresql.org/'
136 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
137 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
138 cdata.set_quoted('PACKAGE_URL', pg_url)
139 cdata.set_quoted('PACKAGE_VERSION', pg_version)
140 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
141 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
143 pg_version += get_option('extra_version')
144 cdata.set_quoted('PG_VERSION', pg_version)
145 cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by @2@-@3@'.format(
146   pg_version, build_machine.cpu_family(), cc.get_id(), cc.version()))
147 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
148 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
149 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
150 cdata.set('PG_VERSION_NUM', pg_version_num)
151 cdata.set_quoted('CONFIGURE_ARGS', '')
155 ###############################################################
156 # Basic platform specific configuration
157 ###############################################################
159 # meson's system names don't quite map to our "traditional" names. In some
160 # places we need the "traditional" name, e.g., for mapping
161 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
162 # that purpose.
163 portname = host_system
165 exesuffix = '' # overridden below where necessary
166 dlsuffix = '.so' # overridden below where necessary
167 library_path_var = 'LD_LIBRARY_PATH'
169 # Format of file to control exports from libraries, and how to pass them to
170 # the compiler. For export_fmt @0@ is the path to the file export file.
171 export_file_format = 'gnu'
172 export_file_suffix = 'list'
173 export_fmt = '-Wl,--version-script=@0@'
175 # Flags to add when linking a postgres extension, @0@ is path to
176 # the relevant object on the platform.
177 mod_link_args_fmt = []
179 memset_loop_limit = 1024
181 # Choice of shared memory and semaphore implementation
182 shmem_kind = 'sysv'
183 sema_kind = 'sysv'
185 # We implement support for some operating systems by pretending they're
186 # another. Map here, before determining system properties below
187 if host_system == 'dragonfly'
188   # apparently the most similar
189   host_system = 'netbsd'
190 endif
192 if host_system == 'aix'
193   library_path_var = 'LIBPATH'
195   export_file_format = 'aix'
196   export_fmt = '-Wl,-bE:@0@'
197   mod_link_args_fmt = ['-Wl,-bI:@0@']
198   mod_link_with_dir = 'libdir'
199   mod_link_with_name = '@0@.imp'
201   # M:SRE sets a flag indicating that an object is a shared library. Seems to
202   # work in some circumstances without, but required in others.
203   ldflags_sl += '-Wl,-bM:SRE'
204   ldflags_be += '-Wl,-brtllib'
206   # Native memset() is faster, tested on:
207   # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
208   # - AIX 5.3 ML3, gcc 4.0.1
209   memset_loop_limit = 0
211 elif host_system == 'cygwin'
212   cppflags += '-D_GNU_SOURCE'
214 elif host_system == 'darwin'
215   dlsuffix = '.dylib'
216   library_path_var = 'DYLD_LIBRARY_PATH'
218   export_file_format = 'darwin'
219   export_fmt = '-exported_symbols_list=@0@'
221   mod_link_args_fmt = ['-bundle_loader', '@0@']
222   mod_link_with_dir = 'bindir'
223   mod_link_with_name = '@0@'
225   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
226   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
227   message('darwin sysroot: @0@'.format(pg_sysroot))
228   cflags += ['-isysroot', pg_sysroot]
229   ldflags += ['-isysroot', pg_sysroot]
231 elif host_system == 'freebsd'
232   sema_kind = 'unnamed_posix'
234 elif host_system == 'linux'
235   sema_kind = 'unnamed_posix'
236   cppflags += '-D_GNU_SOURCE'
238 elif host_system == 'netbsd'
239   # We must resolve all dynamic linking in the core server at program start.
240   # Otherwise the postmaster can self-deadlock due to signals interrupting
241   # resolution of calls, since NetBSD's linker takes a lock while doing that
242   # and some postmaster signal handlers do things that will also acquire that
243   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
244   # While there's not a hard reason to adopt these settings for our other
245   # executables, there's also little reason not to, so just add them to
246   # LDFLAGS.
247   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
249 elif host_system == 'openbsd'
250   # you're ok
252 elif host_system == 'sunos'
253   portname = 'solaris'
254   export_fmt = '-Wl,-M@0@'
255   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
257 elif host_system == 'windows'
258   portname = 'win32'
259   exesuffix = '.exe'
260   dlsuffix = '.dll'
261   library_path_var = ''
263   export_file_format = 'win'
264   export_file_suffix = 'def'
265   if cc.get_id() == 'msvc'
266     export_fmt = '/DEF:@0@'
267     mod_link_with_name = '@0@.exe.lib'
268   else
269     export_fmt = '@0@'
270     mod_link_with_name = 'lib@0@.exe.a'
271   endif
272   mod_link_args_fmt = ['@0@']
273   mod_link_with_dir = 'libdir'
275   shmem_kind = 'win32'
276   sema_kind = 'win32'
278   cdata.set('WIN32_STACK_RLIMIT', 4194304)
279   if cc.get_id() == 'msvc'
280     ldflags += '/INCREMENTAL:NO'
281     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
282     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
283   else
284     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
285     # Need to allow multiple definitions, we e.g. want to override getopt.
286     ldflags += '-Wl,--allow-multiple-definition'
287     # Ensure we get MSVC-like linking behavior.
288     ldflags += '-Wl,--disable-auto-import'
289   endif
291   os_deps += cc.find_library('ws2_32', required: true)
292   secur32_dep = cc.find_library('secur32', required: true)
293   backend_deps += secur32_dep
294   libpq_deps += secur32_dep
296   postgres_inc_d += 'src/include/port/win32'
297   if cc.get_id() == 'msvc'
298     postgres_inc_d += 'src/include/port/win32_msvc'
299   endif
301   windows = import('windows')
303 else
304   # XXX: Should we add an option to override the host_system as an escape
305   # hatch?
306   error('unknown host system: @0@'.format(host_system))
307 endif
311 ###############################################################
312 # Program paths
313 ###############################################################
315 # External programs
316 perl = find_program(get_option('PERL'), required: true, native: true)
317 python = find_program(get_option('PYTHON'), required: true, native: true)
318 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.31')
319 bison = find_program(get_option('BISON'), native: true, version: '>= 1.875')
320 sed = find_program(get_option('SED'), 'sed', native: true)
321 prove = find_program(get_option('PROVE'), native: true)
322 tar = find_program(get_option('TAR'), native: true)
323 gzip = find_program(get_option('GZIP'), native: true)
324 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
325 touch = find_program('touch', native: true)
326 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
327 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
328 missing = find_program('config/missing', native: true)
330 # used by PGXS
331 install_sh = find_program('config/install-sh', native: true)
333 bison_flags = []
334 if bison.found()
335   bison_version_c = run_command(bison, '--version', check: true)
336   # bison version string helpfully is something like
337   # >>bison (GNU bison) 3.8.1<<
338   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
339   if bison_version.version_compare('>=3.0')
340     bison_flags += ['-Wno-deprecated']
341   endif
342 endif
343 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
344 bison_kw = {
345   'output': ['@BASENAME@.c', '@BASENAME@.h'],
346   'command': bison_cmd,
349 flex_flags = []
350 flex_wrapper = files('src/tools/pgflex')
351 flex_cmd = [python, flex_wrapper,
352   '--builddir', '@BUILD_ROOT@',
353   '--srcdir', '@SOURCE_ROOT@',
354   '--privatedir', '@PRIVATE_DIR@',
355   '--flex', flex, '--perl', perl,
356   '-i', '@INPUT@', '-o', '@OUTPUT0@',
359 wget = find_program('wget', required: false, native: true)
360 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
364 ###############################################################
365 # Path to meson (for tests etc)
366 ###############################################################
368 # NB: this should really be part of meson, see
369 # https://github.com/mesonbuild/meson/issues/8511
370 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
372 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
373   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
374     meson_binpath_r.returncode(),
375     meson_binpath_r.stdout(),
376     meson_binpath_r.stderr()))
377 endif
379 meson_binpath_s = meson_binpath_r.stdout().split('\n')
380 meson_binpath_len = meson_binpath_s.length()
382 if meson_binpath_len < 1
383   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
384 endif
386 i = 0
387 meson_impl = ''
388 meson_binpath = ''
389 meson_args = []
390 foreach e : meson_binpath_s
391   if i == 0
392     meson_impl = e
393   elif i == 1
394     meson_binpath = e
395   else
396     meson_args += e
397   endif
398   i += 1
399 endforeach
401 if meson_impl not in ['muon', 'meson']
402   error('unknown meson implementation "@0@"'.format(meson_impl))
403 endif
405 meson_bin = find_program(meson_binpath, native: true)
409 ###############################################################
410 # Option Handling
411 ###############################################################
413 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
415 cdata.set('BLCKSZ', get_option('blocksize').to_int() * 1024, description:
416 '''Size of a disk block --- this also limits the size of a tuple. You can set
417    it bigger if you need bigger tuples (although TOAST should reduce the need
418    to have large tuples, since fields can be spread across multiple tuples).
419    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
420    currently 2^15 (32768). This is determined by the 15-bit widths of the
421    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
422    Changing BLCKSZ requires an initdb.''')
424 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
425 cdata.set('RELSEG_SIZE', get_option('segsize') * 131072)
426 cdata.set('DEF_PGPORT', get_option('pgport'))
427 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
428 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
429 if get_option('system_tzdata') != ''
430   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
431 endif
435 ###############################################################
436 # Directories
437 ###############################################################
439 # These are set by the equivalent --xxxdir configure options.  We
440 # append "postgresql" to some of them, if the string does not already
441 # contain "pgsql" or "postgres", in order to avoid directory clutter.
443 pkg = 'postgresql'
445 dir_prefix = get_option('prefix')
447 dir_bin = get_option('bindir')
449 dir_data = get_option('datadir')
450 if not (dir_data.contains('pgsql') or dir_data.contains('postgres'))
451   dir_data = dir_data / pkg
452 endif
454 dir_sysconf = get_option('sysconfdir')
455 if not (dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
456   dir_sysconf = dir_sysconf / pkg
457 endif
459 dir_lib = get_option('libdir')
461 dir_lib_pkg = dir_lib
462 if not (dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
463   dir_lib_pkg = dir_lib_pkg / pkg
464 endif
466 dir_pgxs = dir_lib_pkg / 'pgxs'
468 dir_include = get_option('includedir')
470 dir_include_pkg = dir_include
471 dir_include_pkg_rel = ''
472 if not (dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
473   dir_include_pkg = dir_include_pkg / pkg
474   dir_include_pkg_rel = pkg
475 endif
477 dir_man = get_option('mandir')
479 # FIXME: These used to be separately configurable - worth adding?
480 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
481 dir_doc_html = dir_doc
483 dir_locale = get_option('localedir')
486 # Derived values
487 dir_bitcode = dir_lib_pkg / 'bitcode'
488 dir_include_internal = dir_include_pkg / 'internal'
489 dir_include_server = dir_include_pkg / 'server'
490 dir_include_extension = dir_include_server / 'extension'
491 dir_data_extension = dir_data / 'extension'
495 ###############################################################
496 # Search paths, preparation for compiler tests
498 # NB: Arguments added later are not automatically used for subsequent
499 # configuration-time checks (so they are more isolated). If they should be
500 # used, they need to be added to test_c_args as well.
501 ###############################################################
503 postgres_inc = [include_directories(postgres_inc_d)]
504 test_lib_d = postgres_lib_d
505 test_c_args = cppflags + cflags
509 ###############################################################
510 # Library: bsd-auth
511 ###############################################################
513 bsd_authopt = get_option('bsd_auth')
514 bsd_auth = not_found_dep
515 if cc.check_header('bsd_auth.h', required: bsd_authopt,
516     args: test_c_args, include_directories: postgres_inc)
517   cdata.set('USE_BSD_AUTH', 1)
518   bsd_auth = declare_dependency()
519 endif
523 ###############################################################
524 # Library: bonjour
526 # For now don't search for DNSServiceRegister in a library - only Apple's
527 # Bonjour implementation, which is always linked, works.
528 ###############################################################
530 bonjouropt = get_option('bonjour')
531 bonjour = dependency('', required : false)
532 if cc.check_header('dns_sd.h', required: bonjouropt,
533     args: test_c_args, include_directories: postgres_inc) and \
534    cc.has_function('DNSServiceRegister',
535     args: test_c_args, include_directories: postgres_inc)
536   cdata.set('USE_BONJOUR', 1)
537   bonjour = declare_dependency()
538 endif
542 ###############################################################
543 # Library: GSSAPI
544 ###############################################################
546 gssapiopt = get_option('gssapi')
547 krb_srvtab = ''
548 have_gssapi = false
549 if not gssapiopt.disabled()
550   gssapi = dependency('krb5-gssapi', required: gssapiopt)
551   have_gssapi = gssapi.found()
553   if not have_gssapi
554   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
555       args: test_c_args, include_directories: postgres_inc)
556     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
557   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
558     cdata.set('HAVE_GSSAPI_H', 1)
559   else
560     have_gssapi = false
561   endif
563   if not have_gssapi
564   elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
565       args: test_c_args, include_directories: postgres_inc)
566     cdata.set('ENABLE_GSS', 1)
568     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
569     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
570   elif gssapiopt.enabled()
571     error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
572   else
573     have_gssapi = false
574   endif
575 endif
576 if not have_gssapi
577   gssapi = not_found_dep
578 endif
582 ###############################################################
583 # Library: ldap
584 ###############################################################
586 ldapopt = get_option('ldap')
587 if ldapopt.disabled()
588   ldap = not_found_dep
589   ldap_r = not_found_dep
590 elif host_system == 'windows'
591   ldap = cc.find_library('wldap32', required: ldapopt)
592   ldap_r = ldap
593 else
594   # macos framework dependency is buggy for ldap (one can argue whether it's
595   # Apple's or meson's fault), leading to an endless recursion with ldap.h
596   # including itself. See https://github.com/mesonbuild/meson/issues/10002
597   # Luckily we only need pkg-config support, so the workaround isn't
598   # complicated.
599   ldap = dependency('ldap', method: 'pkg-config', required: false)
600   ldap_r = ldap
602   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
603   # installed
604   if not ldap.found()
605     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
606       has_headers: 'ldap.h', header_include_directories: postgres_inc)
608     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
609     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
610     # library from a separate OpenLDAP installation).  The most reliable
611     # way to check that is to check for a function introduced in 2.5.
612     if not ldap.found()
613       # don't have ldap, we shouldn't check for ldap_r
614     elif cc.has_function('ldap_verify_credentials',
615         dependencies: ldap, args: test_c_args)
616       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
617     else
619       # Use ldap_r for FE if available, else assume ldap is thread-safe.
620       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
621         has_headers: 'ldap.h', header_include_directories: postgres_inc)
622       if not ldap_r.found()
623         ldap_r = ldap
624       else
625         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
626         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
627       endif
629       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
630       # process.  Check for OpenLDAP versions known not to tolerate doing so;
631       # assume non-OpenLDAP implementations are safe.  The dblink test suite
632       # exercises the hazardous interaction directly.
633       compat_test_code = '''
634 #include <ldap.h>
635 #if !defined(LDAP_VENDOR_VERSION) || \
636      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
637       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
638 choke me
639 #endif
641       if not cc.compiles(compat_test_code,
642           name: 'LDAP implementation compatible',
643           dependencies: ldap, args: test_c_args)
644         warning('''
645 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
646 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
647 *** also uses LDAP will crash on exit.''')
648       endif
649     endif
650   endif
652   # XXX: this shouldn't be tested in the windows case, but should be tested in
653   # the dependency() success case
654   if ldap.found() and cc.has_function('ldap_initialize',
655       dependencies: ldap, args: test_c_args)
656     cdata.set('HAVE_LDAP_INITIALIZE', 1)
657   endif
658 endif
660 if ldap.found()
661   assert(ldap_r.found())
662   cdata.set('USE_LDAP', 1)
663 else
664   assert(not ldap_r.found())
665 endif
669 ###############################################################
670 # Library: LLVM
671 ###############################################################
673 llvmopt = get_option('llvm')
674 if not llvmopt.disabled()
675   add_languages('cpp', required: true, native: false)
676   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
678   if llvm.found()
680     cdata.set('USE_LLVM', 1)
682     cpp = meson.get_compiler('cpp')
684     llvm_binpath = llvm.get_variable(configtool: 'bindir')
686     ccache = find_program('ccache', native: true, required: false)
687     clang = find_program(llvm_binpath / 'clang', required: true)
688   endif
689 else
690   llvm = not_found_dep
691 endif
695 ###############################################################
696 # Library: icu
697 ###############################################################
699 icuopt = get_option('icu')
700 if not icuopt.disabled()
701   icu = dependency('icu-uc', required: icuopt.enabled())
702   icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
704   if icu.found()
705     cdata.set('USE_ICU', 1)
706   endif
708 else
709   icu = not_found_dep
710   icu_i18n = not_found_dep
711 endif
715 ###############################################################
716 # Library: libxml
717 ###############################################################
719 libxmlopt = get_option('libxml')
720 if not libxmlopt.disabled()
721   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
723   if libxml.found()
724     cdata.set('USE_LIBXML', 1)
725   endif
726 else
727   libxml = not_found_dep
728 endif
732 ###############################################################
733 # Library: libxslt
734 ###############################################################
736 libxsltopt = get_option('libxslt')
737 if not libxsltopt.disabled()
738   libxslt = dependency('libxslt', required: libxsltopt)
740   if libxslt.found()
741     cdata.set('USE_LIBXSLT', 1)
742   endif
743 else
744   libxslt = not_found_dep
745 endif
749 ###############################################################
750 # Library: lz4
751 ###############################################################
753 lz4opt = get_option('lz4')
754 if not lz4opt.disabled()
755   lz4 = dependency('liblz4', required: lz4opt)
757   if lz4.found()
758     cdata.set('USE_LZ4', 1)
759     cdata.set('HAVE_LIBLZ4', 1)
760   endif
762 else
763   lz4 = not_found_dep
764 endif
768 ###############################################################
769 # Library: Tcl (for pltcl)
771 # NB: tclConfig.sh is used in autoconf build for getting
772 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
773 # variables. For now we have not seen a need to copy
774 # that behaviour to the meson build.
775 ###############################################################
777 tclopt = get_option('pltcl')
778 tcl_version = get_option('tcl_version')
779 tcl_dep = not_found_dep
780 if not tclopt.disabled()
782   # via pkg-config
783   tcl_dep = dependency(tcl_version, required: false)
785   if not tcl_dep.found()
786     tcl_dep = cc.find_library(tcl_version,
787       required: tclopt,
788       dirs: test_lib_d)
789   endif
791   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
792     tcl_dep = not_found_dep
793   endif
794 endif
798 ###############################################################
799 # Library: pam
800 ###############################################################
802 pamopt = get_option('pam')
803 if not pamopt.disabled()
804   pam = dependency('pam', required: false)
806   if not pam.found()
807     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
808   endif
810   if pam.found()
811     pam_header_found = false
813     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
814     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
815         args: test_c_args, include_directories: postgres_inc)
816       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
817       pam_header_found = true
818     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
819         args: test_c_args, include_directories: postgres_inc)
820       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
821       pam_header_found = true
822     endif
824     if pam_header_found
825       cdata.set('USE_PAM', 1)
826     else
827       pam = not_found_dep
828     endif
829   endif
830 else
831   pam = not_found_dep
832 endif
836 ###############################################################
837 # Library: Perl (for plperl)
838 ###############################################################
840 perlopt = get_option('plperl')
841 perl_dep = not_found_dep
842 if not perlopt.disabled()
843   perl_may_work = true
845   # First verify that perl has the necessary dependencies installed
846   perl_mods = run_command(
847     [perl,
848      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
849      '-e', ''],
850     check: false)
851   if perl_mods.returncode() != 0
852     perl_may_work = false
853     perl_msg = 'perl installation does not have the required modules'
854   endif
856   # Then inquire perl about its configuration
857   if perl_may_work
858     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
859     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
860     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
861     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
862     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
864     perl_inc_dir = '@0@/CORE'.format(archlibexp)
866     if useshrplib != 'true'
867       perl_may_work = false
868       perl_msg = 'need a shared perl'
869     endif
870   endif
872   if perl_may_work
873     # On most platforms, archlibexp is also where the Perl include files live ...
874     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
875     # ... but on newer macOS versions, we must use -iwithsysroot to look
876     # under sysroot
877     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
878        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
879       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
880     endif
882     # check compiler finds header
883     if not cc.has_header('perl.h', required: false,
884         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
885       perl_may_work = false
886       perl_msg = 'missing perl.h'
887     endif
888   endif
890   if perl_may_work
891     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
893     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
894     foreach flag : perl_ccflags_r.split(' ')
895       if flag.startswith('-D') and \
896           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
897         perl_ccflags += flag
898       endif
899     endforeach
901     if host_system == 'windows'
902       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
903     endif
905     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
906     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
908     # We are after Embed's ldopts, but without the subset mentioned in
909     # Config's ccdlflags and ldflags.  (Those are the choices of those who
910     # built the Perl installation, which are not necessarily appropriate
911     # for building PostgreSQL.)
912     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
913     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
914     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
916     perl_ldopts = []
917     foreach ldopt : ldopts.split(' ')
918       if ldopt == '' or ldopt in undesired
919         continue
920       endif
922       perl_ldopts += ldopt.strip('"')
923     endforeach
925     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
926     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
928     perl_dep_int = declare_dependency(
929       compile_args: perl_ccflags,
930       link_args: perl_ldopts,
931       version: perlversion,
932     )
934     # While we're at it, check that we can link to libperl.
935     # On most platforms, if perl.h is there then libperl.so will be too, but
936     # at this writing Debian packages them separately.
937     perl_link_test = '''
938 /* see plperl.h */
939 #ifdef _MSC_VER
940 #define __inline__ inline
941 #endif
942 #include <EXTERN.h>
943 #include <perl.h>
944 int main(void)
946 perl_alloc();
947 }'''
948     if not cc.links(perl_link_test, name: 'libperl',
949           args: test_c_args + perl_ccflags + perl_ldopts,
950           include_directories: postgres_inc)
951       perl_may_work = false
952       perl_msg = 'missing libperl'
953     endif
955   endif # perl_may_work
957   if perl_may_work
958     perl_dep = perl_dep_int
959   else
960     if perlopt.enabled()
961       error('dependency plperl failed: @0@'.format(perl_msg))
962     else
963       message('disabling optional dependency plperl: @0@'.format(perl_msg))
964     endif
965   endif
966 endif
970 ###############################################################
971 # Library: Python (for plpython)
972 ###############################################################
974 pyopt = get_option('plpython')
975 if not pyopt.disabled()
976   pm = import('python')
977   python3_inst = pm.find_installation(required: pyopt.enabled())
978   python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
979   if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
980     python3_dep = not_found_dep
981   endif
982 else
983   python3_dep = not_found_dep
984 endif
988 ###############################################################
989 # Library: Readline
990 ###############################################################
992 if not get_option('readline').disabled()
993   libedit_preferred = get_option('libedit_preferred')
994   # Set the order of readline dependencies
995   check_readline_deps = libedit_preferred ? \
996     ['libedit', 'readline'] : ['readline', 'libedit']
998   foreach readline_dep : check_readline_deps
999     readline = dependency(readline_dep, required: false)
1000     if not readline.found()
1001       readline = cc.find_library(readline_dep,
1002         required: get_option('readline').enabled(),
1003         dirs: test_lib_d)
1004     endif
1005     if readline.found()
1006       break
1007     endif
1008   endforeach
1010   if readline.found()
1011     cdata.set('HAVE_LIBREADLINE', 1)
1013     editline_prefix = {
1014       'header_prefix': 'editline/',
1015       'flag_prefix': 'EDITLINE_',
1016     }
1017     readline_prefix = {
1018       'header_prefix': 'readline/',
1019       'flag_prefix': 'READLINE_',
1020     }
1021     default_prefix = {
1022       'header_prefix': '',
1023       'flag_prefix': '',
1024     }
1026     # Set the order of prefixes
1027     prefixes = libedit_preferred ? \
1028       [editline_prefix, default_prefix, readline_prefix] : \
1029       [readline_prefix, default_prefix, editline_prefix]
1031     at_least_one_header_found = false
1032     foreach header : ['history', 'readline']
1033       is_found = false
1034       foreach prefix : prefixes
1035         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1036         # Check history.h and readline.h
1037         if not is_found and cc.has_header(header_file,
1038             args: test_c_args, include_directories: postgres_inc,
1039             dependencies: [readline], required: false)
1040           if header == 'readline'
1041             readline_h = header_file
1042           endif
1043           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1044           is_found = true
1045           at_least_one_header_found = true
1046         endif
1047       endforeach
1048     endforeach
1050     if not at_least_one_header_found
1051       error('''readline header not found
1052 If you have @0@ already installed, see see meson-log/meson-log.txt for details on the
1053 failure. It is possible the compiler isn't looking in the proper directory.
1054 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1055     endif
1057     check_funcs = [
1058       'append_history',
1059       'history_truncate_file',
1060       'rl_completion_matches',
1061       'rl_filename_completion_function',
1062       'rl_reset_screen_size',
1063       'rl_variable_bind',
1064     ]
1066     foreach func : check_funcs
1067       found = cc.has_function(func, dependencies: [readline],
1068         args: test_c_args, include_directories: postgres_inc)
1069       cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1070     endforeach
1072     check_vars = [
1073       'rl_completion_suppress_quote',
1074       'rl_filename_quote_characters',
1075       'rl_filename_quoting_function',
1076     ]
1078     foreach var : check_vars
1079       cdata.set('HAVE_'+var.to_upper(),
1080         cc.has_header_symbol(readline_h, var,
1081           args: test_c_args, include_directories: postgres_inc,
1082           prefix: '#include <stdio.h>',
1083           dependencies: [readline]) ? 1 : false)
1084     endforeach
1086     # If found via cc.find_library() ensure headers are found when using the
1087     # dependency. On meson < 0.57 one cannot do compiler checks using the
1088     # dependency returned by declare_dependency(), so we can't do this above.
1089     if readline.type_name() == 'library'
1090       readline = declare_dependency(dependencies: readline,
1091         include_directories: postgres_inc)
1092     endif
1094     # On windows with mingw readline requires auto-import to successfully
1095     # link, as the headers don't use declspec(dllimport)
1096     if host_system == 'windows' and cc.get_id() != 'msvc'
1097       readline = declare_dependency(dependencies: readline,
1098         link_args: '-Wl,--enable-auto-import')
1099     endif
1100   endif
1102   # XXX: Figure out whether to implement mingw warning equivalent
1103 else
1104   readline = not_found_dep
1105 endif
1109 ###############################################################
1110 # Library: selinux
1111 ###############################################################
1113 selinux = not_found_dep
1114 selinuxopt = get_option('selinux')
1115 if meson.version().version_compare('>=0.59')
1116   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1117 endif
1118 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1119 cdata.set('HAVE_LIBSELINUX',
1120   selinux.found() ? 1 : false)
1124 ###############################################################
1125 # Library: systemd
1126 ###############################################################
1128 systemd = not_found_dep
1129 systemdopt = get_option('systemd')
1130 if meson.version().version_compare('>=0.59')
1131   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1132 endif
1133 systemd = dependency('libsystemd', required: systemdopt)
1134 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1138 ###############################################################
1139 # Library: SSL
1140 ###############################################################
1142 if get_option('ssl') == 'openssl'
1144   # Try to find openssl via pkg-config et al, if that doesn't work
1145   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1146   # the library names that we know about.
1148   # via pkg-config et al
1149   ssl = dependency('openssl', required: false)
1151   # via library + headers
1152   if not ssl.found()
1153     ssl_lib = cc.find_library('ssl',
1154       dirs: test_lib_d,
1155       header_include_directories: postgres_inc,
1156       has_headers: ['openssl/ssl.h', 'openssl/err.h'])
1157     crypto_lib = cc.find_library('crypto',
1158       dirs: test_lib_d,
1159       header_include_directories: postgres_inc)
1160     ssl_int = [ssl_lib, crypto_lib]
1162     ssl = declare_dependency(dependencies: ssl_int,
1163                              include_directories: postgres_inc)
1164   else
1165     cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
1166     cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
1168     ssl_int = [ssl]
1169   endif
1171   check_funcs = [
1172     ['CRYPTO_new_ex_data', {'required': true}],
1173     ['SSL_new', {'required': true}],
1175     # Function introduced in OpenSSL 1.0.2.
1176     ['X509_get_signature_nid'],
1178     # Functions introduced in OpenSSL 1.1.0. We used to check for
1179     # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1180     # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1181     # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1182     # functions.
1183     ['OPENSSL_init_ssl'],
1184     ['BIO_get_data'],
1185     ['BIO_meth_new'],
1186     ['ASN1_STRING_get0_data'],
1187     ['HMAC_CTX_new'],
1188     ['HMAC_CTX_free'],
1190     # OpenSSL versions before 1.1.0 required setting callback functions, for
1191     # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1192     # function was removed.
1193     ['CRYPTO_lock'],
1194   ]
1196   foreach c : check_funcs
1197     func = c.get(0)
1198     val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1199     required = c.get(1, {}).get('required', false)
1200     if required and not val
1201       error('openssl function @0@ is required'.format(func))
1202     elif not required
1203       cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1204     endif
1205   endforeach
1207   cdata.set('USE_OPENSSL', 1,
1208             description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1209   cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1210             description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1211 else
1212   ssl = not_found_dep
1213 endif
1217 ###############################################################
1218 # Library: uuid
1219 ###############################################################
1221 uuidopt = get_option('uuid')
1222 if uuidopt != 'none'
1223   uuidname = uuidopt.to_upper()
1224   if uuidopt == 'e2fs'
1225     uuid = dependency('uuid', required: true)
1226     uuidfunc = 'uuid_generate'
1227     uuidheader = 'uuid/uuid.h'
1228   elif uuidopt == 'bsd'
1229     # libc should have uuid function
1230     uuid = declare_dependency()
1231     uuidfunc = 'uuid_to_string'
1232     uuidheader = 'uuid.h'
1233   elif uuidopt == 'ossp'
1234     uuid = dependency('ossp-uuid', required: true)
1235     uuidfunc = 'uuid_export'
1236     uuidheader = 'ossp/uuid.h'
1237   else
1238     error('huh')
1239   endif
1241   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1242     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1243   endif
1244   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1246   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1247            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1248 else
1249   uuid = not_found_dep
1250 endif
1254 ###############################################################
1255 # Library: zlib
1256 ###############################################################
1258 zlibopt = get_option('zlib')
1259 zlib = not_found_dep
1260 if not zlibopt.disabled()
1261   zlib_t = dependency('zlib', required: zlibopt)
1263   if zlib_t.type_name() == 'internal'
1264     # if fallback was used, we don't need to test if headers are present (they
1265     # aren't built yet, so we can't test)
1266     zlib = zlib_t
1267   elif not zlib_t.found()
1268     warning('did not find zlib')
1269   elif not cc.has_header('zlib.h',
1270       args: test_c_args, include_directories: postgres_inc,
1271       dependencies: [zlib_t], required: zlibopt.enabled())
1272     warning('zlib header not found')
1273   elif not cc.has_type('z_streamp',
1274       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1275       args: test_c_args, include_directories: postgres_inc)
1276     if zlibopt.enabled()
1277       error('zlib version is too old')
1278     else
1279       warning('zlib version is too old')
1280     endif
1281   else
1282     zlib = zlib_t
1283   endif
1285   if zlib.found()
1286     cdata.set('HAVE_LIBZ', 1)
1287   endif
1288 endif
1292 ###############################################################
1293 # Library: tap test dependencies
1294 ###############################################################
1296 # Check whether tap tests are enabled or not
1297 tap_tests_enabled = false
1298 tapopt = get_option('tap_tests')
1299 if not tapopt.disabled()
1300   # Checking for perl modules for tap tests
1301   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1302   if perl_ipc_run_check.returncode() != 0
1303     message(perl_ipc_run_check.stderr().strip())
1304     if tapopt.enabled()
1305       error('Additional Perl modules are required to run TAP tests.')
1306     else
1307       warning('Additional Perl modules are required to run TAP tests.')
1308     endif
1309   else
1310     tap_tests_enabled = true
1311   endif
1312 endif
1316 ###############################################################
1317 # Library: zstd
1318 ###############################################################
1320 zstdopt = get_option('zstd')
1321 if not zstdopt.disabled()
1322   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1324   if zstd.found()
1325     cdata.set('USE_ZSTD', 1)
1326     cdata.set('HAVE_LIBZSTD', 1)
1327   endif
1329 else
1330   zstd = not_found_dep
1331 endif
1335 ###############################################################
1336 # Compiler tests
1337 ###############################################################
1339 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1340 # unnecessarily, because we optionally rely on newer features.
1341 c99_test = '''
1342 #include <stdbool.h>
1343 #include <complex.h>
1344 #include <tgmath.h>
1345 #include <inttypes.h>
1347 struct named_init_test {
1348   int a;
1349   int b;
1352 extern void structfunc(struct named_init_test);
1354 int main(int argc, char **argv)
1356   struct named_init_test nit = {
1357     .a = 3,
1358     .b = 5,
1359   };
1361   for (int loop_var = 0; loop_var < 3; loop_var++)
1362   {
1363     nit.a += nit.b;
1364   }
1366   structfunc((struct named_init_test){1, 0});
1368   return nit.a != 0;
1372 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1373   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1374         args: test_c_args + ['-std=c99'])
1375     test_c_args += '-std=c99'
1376     cflags += '-std=c99'
1377   else
1378     error('C compiler does not support C99')
1379   endif
1380 endif
1382 sizeof_long = cc.sizeof('long', args: test_c_args)
1383 cdata.set('SIZEOF_LONG', sizeof_long)
1384 if sizeof_long == 8
1385   cdata.set('HAVE_LONG_INT_64', 1)
1386   cdata.set('PG_INT64_TYPE', 'long int')
1387   cdata.set_quoted('INT64_MODIFIER', 'l')
1388 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1389   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1390   cdata.set('PG_INT64_TYPE', 'long long int')
1391   cdata.set_quoted('INT64_MODIFIER', 'll')
1392 else
1393   error('do not know how to get a 64bit int')
1394 endif
1396 if host_machine.endian() == 'big'
1397   cdata.set('WORDS_BIGENDIAN', 1)
1398 endif
1400 alignof_types = ['short', 'int', 'long', 'double']
1401 maxalign = 0
1402 foreach t : alignof_types
1403   align = cc.alignment(t, args: test_c_args)
1404   if maxalign < align
1405     maxalign = align
1406   endif
1407   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1408 endforeach
1409 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1411 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1412 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1415 # Check if __int128 is a working 128 bit integer type, and if so
1416 # define PG_INT128_TYPE to that typename.
1418 # This currently only detects a GCC/clang extension, but support for other
1419 # environments may be added in the future.
1421 # For the moment we only test for support for 128bit math; support for
1422 # 128bit literals and snprintf is not required.
1423 if cc.links('''
1424   /*
1425    * We don't actually run this test, just link it to verify that any support
1426    * functions needed for __int128 are present.
1427    *
1428    * These are globals to discourage the compiler from folding all the
1429    * arithmetic tests down to compile-time constants.  We do not have
1430    * convenient support for 128bit literals at this point...
1431    */
1432   __int128 a = 48828125;
1433   __int128 b = 97656250;
1435   int main(void)
1436   {
1437       __int128 c,d;
1438       a = (a << 12) + 1; /* 200000000001 */
1439       b = (b << 12) + 5; /* 400000000005 */
1440       /* try the most relevant arithmetic ops */
1441       c = a * b;
1442       d = (c + b) / b;
1443       /* must use the results, else compiler may optimize arithmetic away */
1444       return d != a+1;
1445   }''',
1446   name: '__int128',
1447   args: test_c_args)
1449   buggy_int128 = false
1451   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1452   # If not cross-compiling, we can test for bugs and disable use of __int128
1453   # with buggy compilers.  If cross-compiling, hope for the best.
1454   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1455   if not meson.is_cross_build()
1456     r = cc.run('''
1457     /* This must match the corresponding code in c.h: */
1458     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1459     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1460     #endif
1461     typedef __int128 int128a
1462     #if defined(pg_attribute_aligned)
1463     pg_attribute_aligned(8)
1464     #endif
1465     ;
1467     int128a holder;
1468     void pass_by_val(void *buffer, int128a par) { holder = par; }
1470     int main(void)
1471     {
1472         long int i64 = 97656225L << 12;
1473         int128a q;
1474         pass_by_val(main, (int128a) i64);
1475         q = (int128a) i64;
1476         return q != holder;
1477     }''',
1478     name: '__int128 alignment bug',
1479     args: test_c_args)
1480     assert(r.compiled())
1481     if r.returncode() != 0
1482       buggy_int128 = true
1483       message('__int128 support present but buggy and thus disabled')
1484     endif
1485   endif
1487   if not buggy_int128
1488     cdata.set('PG_INT128_TYPE', '__int128')
1489     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1490       alignment('__int128', args: test_c_args))
1491   endif
1492 endif
1495 # Check if the C compiler knows computed gotos (gcc extension, also
1496 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1498 # Checking whether computed gotos are supported syntax-wise ought to
1499 # be enough, as the syntax is otherwise illegal.
1500 if cc.compiles('''
1501     static inline int foo(void)
1502     {
1503       void *labeladdrs[] = {&&my_label};
1504       goto *labeladdrs[0];
1505       my_label:
1506       return 1;
1507     }''',
1508     args: test_c_args)
1509   cdata.set('HAVE_COMPUTED_GOTO', 1)
1510 endif
1513 # Check if the C compiler understands _Static_assert(),
1514 # and define HAVE__STATIC_ASSERT if so.
1516 # We actually check the syntax ({ _Static_assert(...) }), because we need
1517 # gcc-style compound expressions to be able to wrap the thing into macros.
1518 if cc.compiles('''
1519     int main(int arg, char **argv)
1520     {
1521         ({ _Static_assert(1, "foo"); });
1522     }
1523     ''',
1524     args: test_c_args)
1525   cdata.set('HAVE__STATIC_ASSERT', 1)
1526 endif
1529 # We use <stdbool.h> if we have it and it declares type bool as having
1530 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1531 if cc.has_type('_Bool', args: test_c_args) \
1532   and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1533   and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1534   cdata.set('HAVE__BOOL', 1)
1535   cdata.set('PG_USE_STDBOOL', 1)
1536 endif
1539 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1540 # warning for each use of %m.
1541 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1542 testsrc = '''
1543 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1544 static void call_log(void)
1546     emit_log(0, "error: %s: %m", "foo");
1549 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1550 foreach a : printf_attributes
1551   if cc.compiles(testsrc.format(a),
1552       args: test_c_args + attrib_error_args, name: 'format ' + a)
1553     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1554     break
1555   endif
1556 endforeach
1559 if cc.has_function_attribute('visibility:default') and \
1560   cc.has_function_attribute('visibility:hidden')
1561   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1563   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1564   # inlineshidden to C code as well... Any either way, we want to put these
1565   # flags into exported files (pgxs, .pc files).
1566   cflags_mod += '-fvisibility=hidden'
1567   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1568   ldflags_mod += '-fvisibility=hidden'
1569 endif
1572 # Check if various builtins exist. Some builtins are tested separately,
1573 # because we want to test something more complicated than the generic case.
1574 builtins = [
1575   'bswap16',
1576   'bswap32',
1577   'bswap64',
1578   'clz',
1579   'ctz',
1580   'constant_p',
1581   'frame_address',
1582   'popcount',
1583   'unreachable',
1586 foreach builtin : builtins
1587   fname = '__builtin_@0@'.format(builtin)
1588   if cc.has_function(fname, args: test_c_args)
1589     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1590   endif
1591 endforeach
1594 # Check if the C compiler understands __builtin_types_compatible_p,
1595 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1597 # We check usage with __typeof__, though it's unlikely any compiler would
1598 # have the former and not the latter.
1599 if cc.compiles('''
1600     static int x;
1601     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1602     ''',
1603     name: '__builtin_types_compatible_p',
1604     args: test_c_args)
1605   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1606 endif
1609 # Check if the C compiler understands __builtin_$op_overflow(),
1610 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1612 # Check for the most complicated case, 64 bit multiplication, as a
1613 # proxy for all of the operations.  To detect the case where the compiler
1614 # knows the function but library support is missing, we must link not just
1615 # compile, and store the results in global variables so the compiler doesn't
1616 # optimize away the call.
1617 if cc.links('''
1618     INT64 a = 1;
1619     INT64 b = 1;
1620     INT64 result;
1622     int main(void)
1623     {
1624         return __builtin_mul_overflow(a, b, &result);
1625     }''',
1626     name: '__builtin_mul_overflow',
1627     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1628     )
1629   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1630 endif
1633 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1634 # here. To prevent problems due to two detection methods working, stop
1635 # checking after one.
1636 if cc.links('''
1637     #include <cpuid.h>
1638     int main(int arg, char **argv)
1639     {
1640         unsigned int exx[4] = {0, 0, 0, 0};
1641         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1642     }
1643     ''', name: '__get_cpuid',
1644     args: test_c_args)
1645   cdata.set('HAVE__GET_CPUID', 1)
1646 elif cc.links('''
1647     #include <intrin.h>
1648     int main(int arg, char **argv)
1649     {
1650         unsigned int exx[4] = {0, 0, 0, 0};
1651         __cpuid(exx, 1);
1652     }
1653     ''', name: '__cpuid',
1654     args: test_c_args)
1655   cdata.set('HAVE__CPUID', 1)
1656 endif
1659 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1660 # versions of clang do not understand -fexcess-precision=standard, the use of
1661 # x87 floating point operations leads to problems like isinf possibly returning
1662 # false for a value that is infinite when converted from the 80bit register to
1663 # the 8byte memory representation.
1665 # Only perform the test if the compiler doesn't understand
1666 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1667 # automatically.
1668 if '-fexcess-precision=standard' not in cflags
1669   if not cc.compiles('''
1670 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1671 choke me
1672 #endif''',
1673       name: '', args: test_c_args)
1674     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1675   endif
1676 endif
1680 ###############################################################
1681 # Compiler flags
1682 ###############################################################
1684 common_functional_flags = [
1685   # Disable strict-aliasing rules; needed for gcc 3.3+
1686   '-fno-strict-aliasing',
1687   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1688   '-fwrapv',
1689   '-fexcess-precision=standard',
1692 cflags += cc.get_supported_arguments(common_functional_flags)
1693 if llvm.found()
1694   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1695 endif
1697 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1698 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1700 common_warning_flags = [
1701   '-Wmissing-prototypes',
1702   '-Wpointer-arith',
1703   # Really don't want VLAs to be used in our dialect of C
1704   '-Werror=vla',
1705   # On macOS, complain about usage of symbols newer than the deployment target
1706   '-Werror=unguarded-availability-new',
1707   '-Wendif-labels',
1708   '-Wmissing-format-attribute',
1709   '-Wimplicit-fallthrough=3',
1710   '-Wcast-function-type',
1711   # This was included in -Wall/-Wformat in older GCC versions
1712   '-Wformat-security',
1715 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1716 if llvm.found()
1717   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1718 endif
1720 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1721 # the result for them
1722 if cc.has_argument('-Wdeclaration-after-statement')
1723   cflags_warn += '-Wdeclaration-after-statement'
1724   using_declaration_after_statement_warning = true
1725 else
1726   using_declaration_after_statement_warning = false
1727 endif
1730 # The following tests want to suppress various unhelpful warnings by adding
1731 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1732 # switches, so we have to test for the positive form and if that works,
1733 # add the negative form.
1735 negative_warning_flags = [
1736   # Suppress clang's unhelpful unused-command-line-argument warnings.
1737   'unused-command-line-argument',
1739   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1740   # of warnings when building plperl because of usages in the Perl headers.
1741   'compound-token-split-by-macro',
1743   # Similarly disable useless truncation warnings from gcc 8+
1744   'format-truncation',
1745   'stringop-truncation',
1747   # To make warning_level=2 / -Wextra work, we'd need at least the following
1748   # 'clobbered',
1749   # 'missing-field-initializers',
1750   # 'sign-compare',
1751   # 'unused-parameter',
1754 foreach w : negative_warning_flags
1755   if cc.has_argument('-W' + w)
1756     cflags_warn += '-Wno-' + w
1757   endif
1758   if llvm.found() and cpp.has_argument('-W' + w)
1759     cxxflags_warn += '-Wno-' + w
1760   endif
1761 endforeach
1764 # From Project.pm
1765 if cc.get_id() == 'msvc'
1766   cflags_warn += [
1767     '/wd4018', # signed/unsigned mismatch
1768     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1769     '/wd4273', # inconsistent DLL linkage
1770     '/wd4101', # unreferenced local variable
1771     '/wd4102', # unreferenced label
1772     '/wd4090', # different 'modifier' qualifiers
1773     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1774   ]
1776   cppflags += [
1777     '/DWIN32',
1778     '/DWINDOWS',
1779     '/D__WINDOWS__',
1780     '/D__WIN32__',
1781     '/D_CRT_SECURE_NO_DEPRECATE',
1782     '/D_CRT_NONSTDC_NO_DEPRECATE',
1783   ]
1785   # We never need export libraries. As link.exe reports their creation, they
1786   # are unnecessarily noisy. Similarly, we don't need import library for
1787   # modules, we only import them dynamically, and they're also noisy.
1788   ldflags += '/NOEXP'
1789   ldflags_mod += '/NOIMPLIB'
1790 endif
1794 ###############################################################
1795 # Atomics
1796 ###############################################################
1798 if not get_option('spinlocks')
1799   warning('Not using spinlocks will cause poor performance')
1800 else
1801   cdata.set('HAVE_SPINLOCKS', 1)
1802 endif
1804 if not get_option('atomics')
1805   warning('Not using atomics will cause poor performance')
1806 else
1807   # XXX: perhaps we should require some atomics support in this case these
1808   # days?
1809   cdata.set('HAVE_ATOMICS', 1)
1811   atomic_checks = [
1812     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1813      'desc': '__sync_lock_test_and_set(char)',
1814      'test': '''
1815 char lock = 0;
1816 __sync_lock_test_and_set(&lock, 1);
1817 __sync_lock_release(&lock);'''},
1819     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1820      'desc': '__sync_lock_test_and_set(int32)',
1821      'test': '''
1822 int lock = 0;
1823 __sync_lock_test_and_set(&lock, 1);
1824 __sync_lock_release(&lock);'''},
1826     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1827      'desc': '__sync_val_compare_and_swap(int32)',
1828      'test': '''
1829 int val = 0;
1830 __sync_val_compare_and_swap(&val, 0, 37);'''},
1832     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1833      'desc': '__sync_val_compare_and_swap(int64)',
1834      'test': '''
1835 INT64 val = 0;
1836 __sync_val_compare_and_swap(&val, 0, 37);'''},
1838     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1839      'desc': ' __atomic_compare_exchange_n(int32)',
1840      'test': '''
1841 int val = 0;
1842 int expect = 0;
1843 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1845     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1846      'desc': ' __atomic_compare_exchange_n(int64)',
1847      'test': '''
1848 INT64 val = 0;
1849 INT64 expect = 0;
1850 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1851   ]
1853   foreach check : atomic_checks
1854     test = '''
1855 int main(void)
1858 }'''.format(check['test'])
1860     cdata.set(check['name'],
1861       cc.links(test,
1862         name: check['desc'],
1863         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1864     )
1865   endforeach
1867 endif
1871 ###############################################################
1872 # Select CRC-32C implementation.
1874 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1875 # use the special CRC instructions for calculating CRC-32C. If we're not
1876 # targeting such a processor, but we can nevertheless produce code that uses
1877 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1878 # implementations and select which one to use at runtime, depending on whether
1879 # SSE 4.2 is supported by the processor we're running on.
1881 # Similarly, if we are targeting an ARM processor that has the CRC
1882 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1883 # we're not targeting such a processor, but can nevertheless produce code that
1884 # uses the CRC instructions, compile both, and select at runtime.
1885 ###############################################################
1887 have_optimized_crc = false
1888 cflags_crc = []
1889 if host_cpu == 'x86' or host_cpu == 'x86_64'
1891   if cc.get_id() == 'msvc'
1892     cdata.set('USE_SSE42_CRC32C', false)
1893     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1894     have_optimized_crc = true
1895   else
1897     prog = '''
1898 #include <nmmintrin.h>
1900 int main(void)
1902     unsigned int crc = 0;
1903     crc = _mm_crc32_u8(crc, 0);
1904     crc = _mm_crc32_u32(crc, 0);
1905     /* return computed value, to prevent the above being optimized away */
1906     return crc == 0;
1910     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
1911           args: test_c_args)
1912       # Use Intel SSE 4.2 unconditionally.
1913       cdata.set('USE_SSE42_CRC32C', 1)
1914       have_optimized_crc = true
1915     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
1916           args: test_c_args + ['-msse4.2'])
1917       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
1918       # the runtime check.
1919       cflags_crc += '-msse4.2'
1920       cdata.set('USE_SSE42_CRC32C', false)
1921       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1922       have_optimized_crc = true
1923     endif
1925   endif
1927 elif host_cpu == 'arm' or host_cpu == 'aarch64'
1929   prog = '''
1930 #include <arm_acle.h>
1932 int main(void)
1934     unsigned int crc = 0;
1935     crc = __crc32cb(crc, 0);
1936     crc = __crc32ch(crc, 0);
1937     crc = __crc32cw(crc, 0);
1938     crc = __crc32cd(crc, 0);
1940     /* return computed value, to prevent the above being optimized away */
1941     return crc == 0;
1945   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
1946       args: test_c_args)
1947     # Use ARM CRC Extension unconditionally
1948     cdata.set('USE_ARMV8_CRC32C', 1)
1949     have_optimized_crc = true
1950   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
1951       args: test_c_args + ['-march=armv8-a+crc'])
1952     # Use ARM CRC Extension, with runtime check
1953     cflags_crc += '-march=armv8-a+crc'
1954     cdata.set('USE_ARMV8_CRC32C', false)
1955     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
1956     have_optimized_crc = true
1957   endif
1958 endif
1960 if not have_optimized_crc
1961   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
1962   # support.
1963   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
1964 endif
1968 ###############################################################
1969 # Other CPU specific stuff
1970 ###############################################################
1972 if host_cpu == 'x86_64'
1974   if cc.compiles('''
1975       void main(void)
1976       {
1977           long long x = 1; long long r;
1978           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
1979       }''',
1980       name: '@0@: popcntq instruction'.format(host_cpu),
1981       args: test_c_args)
1982     cdata.set('HAVE_X86_64_POPCNTQ', 1)
1983   endif
1985 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
1986   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
1987   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
1988     if cc.compiles('''
1989       static inline int
1990       addi(int ra, int si)
1991       {
1992           int res = 0;
1993           if (__builtin_constant_p(si))
1994               __asm__ __volatile__(
1995                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
1996           return res;
1997       }
1998       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
1999       ''',
2000       args: test_c_args)
2001       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2002     endif
2003   endif
2004 endif
2008 ###############################################################
2009 # Library / OS tests
2010 ###############################################################
2012 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2013 # unnecessary checks over and over, particularly on windows.
2014 header_checks = [
2015   'atomic.h',
2016   'copyfile.h',
2017   'crtdefs.h',
2018   'execinfo.h',
2019   'getopt.h',
2020   'ifaddrs.h',
2021   'langinfo.h',
2022   'mbarrier.h',
2023   'stdbool.h',
2024   'strings.h',
2025   'sys/epoll.h',
2026   'sys/event.h',
2027   'sys/personality.h',
2028   'sys/prctl.h',
2029   'sys/procctl.h',
2030   'sys/signalfd.h',
2031   'sys/ucred.h',
2032   'termios.h',
2033   'ucred.h',
2036 foreach header : header_checks
2037   varname = 'HAVE_' + header.underscorify().to_upper()
2039   # Emulate autoconf behaviour of not-found->undef, found->1
2040   found = cc.has_header(header,
2041     include_directories: postgres_inc, args: test_c_args)
2042   cdata.set(varname, found ? 1 : false,
2043             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2044 endforeach
2047 decl_checks = [
2048   ['F_FULLFSYNC', 'fcntl.h'],
2049   ['fdatasync', 'unistd.h'],
2050   ['posix_fadvise', 'fcntl.h'],
2051   ['strlcat', 'string.h'],
2052   ['strlcpy', 'string.h'],
2053   ['strnlen', 'string.h'],
2056 # Need to check for function declarations for these functions, because
2057 # checking for library symbols wouldn't handle deployment target
2058 # restrictions on macOS
2059 decl_checks += [
2060   ['preadv', 'sys/uio.h'],
2061   ['pwritev', 'sys/uio.h'],
2064 foreach c : decl_checks
2065   func = c.get(0)
2066   header = c.get(1)
2067   args = c.get(2, {})
2068   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2070   found = cc.has_header_symbol(header, func,
2071     args: test_c_args, include_directories: postgres_inc,
2072     kwargs: args)
2073   cdata.set10(varname, found, description:
2074 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2075    don't.'''.format(func))
2076 endforeach
2079 if cc.has_type('struct cmsgcred',
2080     args: test_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? '' : '-DHAVE_SYS_UCRED_H'],
2081     include_directories: postgres_inc,
2082     prefix: '''
2083 #include <sys/socket.h>
2084 #include <sys/param.h>
2085 #ifdef HAVE_SYS_UCRED_H
2086 #include <sys/ucred.h>
2087 #endif''')
2088   cdata.set('HAVE_STRUCT_CMSGCRED', 1)
2089 else
2090   cdata.set('HAVE_STRUCT_CMSGCRED', false)
2091 endif
2093 if cc.has_type('struct option',
2094     args: test_c_args, include_directories: postgres_inc,
2095     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2096   cdata.set('HAVE_STRUCT_OPTION', 1)
2097 endif
2100 foreach c : ['opterr', 'optreset']
2101   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2103   if cc.links('''
2104 #include <unistd.h>
2105 int main(void)
2107     extern int @0@;
2108     @0@ = 1;
2110 '''.format(c), name: c, args: test_c_args)
2111     cdata.set(varname, 1)
2112   else
2113     cdata.set(varname, false)
2114   endif
2115 endforeach
2117 if cc.has_type('socklen_t',
2118     args: test_c_args, include_directories: postgres_inc,
2119     prefix: '''
2120 #include <sys/socket.h>''')
2121   cdata.set('HAVE_SOCKLEN_T', 1)
2122 endif
2124 if cc.has_member('struct sockaddr', 'sa_len',
2125     args: test_c_args, include_directories: postgres_inc,
2126     prefix: '''
2127 #include <sys/types.h>
2128 #include <sys/socket.h>''')
2129   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2130 endif
2132 if cc.has_member('struct tm', 'tm_zone',
2133     args: test_c_args, include_directories: postgres_inc,
2134     prefix: '''
2135 #include <sys/types.h>
2136 #include <time.h>
2137 ''')
2138   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2139 endif
2141 if cc.compiles('''
2142 #include <time.h>
2143 extern int foo(void);
2144 int foo(void)
2146     return timezone / 60;
2148 ''',
2149     name: 'global variable `timezone\' exists',
2150     args: test_c_args, include_directories: postgres_inc)
2151   cdata.set('HAVE_INT_TIMEZONE', 1)
2152 else
2153   cdata.set('HAVE_INT_TIMEZONE', false)
2154 endif
2156 if cc.has_type('union semun',
2157     args: test_c_args,
2158     include_directories: postgres_inc,
2159     prefix: '''
2160 #include <sys/types.h>
2161 #include <sys/ipc.h>
2162 #include <sys/sem.h>
2163 ''')
2164   cdata.set('HAVE_UNION_SEMUN', 1)
2165 endif
2167 if cc.compiles('''
2168 #include <string.h>
2169 int main(void)
2171   char buf[100];
2172   switch (strerror_r(1, buf, sizeof(buf)))
2173   { case 0: break; default: break; }
2174 }''',
2175     name: 'strerror_r',
2176     args: test_c_args, include_directories: postgres_inc)
2177   cdata.set('STRERROR_R_INT', 1)
2178 else
2179   cdata.set('STRERROR_R_INT', false)
2180 endif
2182 # Check for the locale_t type and find the right header file.  macOS
2183 # needs xlocale.h; standard is locale.h, but glibc also has an
2184 # xlocale.h file that we should not use.
2185 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2186   cdata.set('HAVE_LOCALE_T', 1)
2187 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2188   cdata.set('HAVE_LOCALE_T', 1)
2189   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2190 endif
2192 # Check if the C compiler understands typeof or a variant.  Define
2193 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2194 foreach kw : ['typeof', '__typeof__', 'decltype']
2195   if cc.compiles('''
2196 int main(void)
2198     int x = 0;
2199     @0@(x) y;
2200     y = x;
2201     return y;
2203 '''.format(kw),
2204     name: 'typeof()',
2205     args: test_c_args, include_directories: postgres_inc)
2207     cdata.set('HAVE_TYPEOF', 1)
2208     if kw != 'typeof'
2209       cdata.set('typeof', kw)
2210     endif
2212     break
2213   endif
2214 endforeach
2217 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2218 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2219 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2220 wcstombs_l_test = '''
2221 #include <stdlib.h>
2222 #include <locale.h>
2225 void main(void)
2227 #ifndef wcstombs_l
2228     (void) wcstombs_l;
2229 #endif
2232 if (not cc.compiles(wcstombs_l_test.format(''),
2233       name: 'wcstombs_l') and
2234     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2235       name: 'wcstombs_l in xlocale.h'))
2236     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2237 endif
2240 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2241 # understands, because it conflicts with __declspec(restrict). Therefore we
2242 # define pg_restrict to the appropriate definition, which presumably won't
2243 # conflict.
2245 # We assume C99 support, so we don't need to make this conditional.
2247 # XXX: Historically we allowed platforms to disable restrict in template
2248 # files, but that was only added for AIX when building with XLC, which we
2249 # don't support yet.
2250 cdata.set('pg_restrict', '__restrict')
2253 if cc.links('''
2254 #include <machine/vmparam.h>
2255 #include <sys/exec.h>
2257 int main(void)
2259     PS_STRINGS->ps_nargvstr = 1;
2260     PS_STRINGS->ps_argvstr = "foo";
2262 ''',
2263   name: 'PS_STRINGS', args: test_c_args)
2264   cdata.set('HAVE_PS_STRINGS', 1)
2265 else
2266   cdata.set('HAVE_PS_STRINGS', false)
2267 endif
2270 # Most libraries are included only if they demonstrably provide a function we
2271 # need, but libm is an exception: always include it, because there are too
2272 # many compilers that play cute optimization games that will break probes for
2273 # standard functions such as pow().
2274 os_deps += cc.find_library('m', required: false)
2276 rt_dep = cc.find_library('rt', required: false)
2278 dl_dep = cc.find_library('dl', required: false)
2280 util_dep = cc.find_library('util', required: false)
2281 posix4_dep = cc.find_library('posix4', required: false)
2283 getopt_dep = cc.find_library('getopt', required: false)
2284 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2285 # Check if we want to replace getopt/getopt_long even if provided by the system
2286 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2287 #   so always use our version on Windows
2288 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2289 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2290 # - We want to use system's getopt_long() only if the system provides struct
2291 #   option
2292 always_replace_getopt = host_system in ['windows', 'openbsd', 'solaris']
2293 always_replace_getopt_long = host_system == 'windows' or not cdata.has('HAVE_STRUCT_OPTION')
2295 # Required on BSDs
2296 execinfo_dep = cc.find_library('execinfo', required: false)
2298 if host_system == 'cygwin'
2299   cygipc_dep = cc.find_library('cygipc', required: false)
2300 else
2301   cygipc_dep = not_found_dep
2302 endif
2304 if host_system == 'sunos'
2305   socket_dep = cc.find_library('socket', required: false)
2306 else
2307   socket_dep = not_found_dep
2308 endif
2310 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2311 # unnecessary checks over and over, particularly on windows.
2312 func_checks = [
2313   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2314   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2315   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2316   ['copyfile'],
2317   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2318   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2319   # required. Just checking for dlsym() ought to suffice.
2320   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2321   ['explicit_bzero'],
2322   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2323   ['getifaddrs'],
2324   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2325   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2326   ['getpeereid'],
2327   ['getpeerucred'],
2328   ['inet_aton'],
2329   ['inet_pton'],
2330   ['kqueue'],
2331   ['mbstowcs_l'],
2332   ['memset_s'],
2333   ['mkdtemp'],
2334   ['posix_fadvise'],
2335   ['posix_fallocate'],
2336   ['ppoll'],
2337   ['pstat'],
2338   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2339   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2340   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2341   ['setproctitle', {'dependencies': [util_dep]}],
2342   ['setproctitle_fast'],
2343   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2344   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2345   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2346   ['socket', {'dependencies': [socket_dep], 'define': false}],
2347   ['strchrnul'],
2348   ['strerror_r', {'dependencies': [thread_dep]}],
2349   ['strlcat'],
2350   ['strlcpy'],
2351   ['strnlen'],
2352   ['strsignal'],
2353   ['sync_file_range'],
2354   ['syncfs'],
2355   ['uselocale'],
2356   ['wcstombs_l'],
2359 func_check_results = {}
2360 foreach c : func_checks
2361   func = c.get(0)
2362   kwargs = c.get(1, {})
2363   deps = kwargs.get('dependencies', [])
2365   if kwargs.get('skip', false)
2366     continue
2367   endif
2369   found = cc.has_function(func, args: test_c_args)
2371   if not found
2372     foreach dep : deps
2373       if not dep.found()
2374         continue
2375       endif
2376       found = cc.has_function(func, args: test_c_args,
2377                               dependencies: [dep])
2378       if found
2379         os_deps += dep
2380         break
2381       endif
2382     endforeach
2383   endif
2385   func_check_results += {func: found}
2387   if kwargs.get('define', true)
2388     # Emulate autoconf behaviour of not-found->undef, found->1
2389     cdata.set('HAVE_' + func.underscorify().to_upper(),
2390               found  ? 1 : false,
2391               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2392   endif
2393 endforeach
2396 if cc.has_function('syslog', args: test_c_args) and \
2397     cc.check_header('syslog.h', args: test_c_args)
2398   cdata.set('HAVE_SYSLOG', 1)
2399 endif
2402 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2403 # semaphores
2404 if sema_kind == 'unnamed_posix' and \
2405    not func_check_results.get('sem_init', false)
2406   sema_kind = 'sysv'
2407 endif
2409 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2410 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2412 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2413 cdata.set_quoted('DLSUFFIX', dlsuffix)
2417 ###############################################################
2418 # Threading
2419 ###############################################################
2421 # XXX: About to rely on thread safety in the autoconf build, so not worth
2422 # implementing a fallback.
2423 cdata.set('ENABLE_THREAD_SAFETY', 1)
2427 ###############################################################
2428 # NLS / Gettext
2429 ###############################################################
2431 nlsopt = get_option('nls')
2432 libintl = not_found_dep
2434 if not nlsopt.disabled()
2435   # otherwise there'd be lots of
2436   # "Gettext not found, all translation (po) targets will be ignored."
2437   # warnings if not found.
2438   msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2440   # meson 0.59 has this wrapped in dependency('int')
2441   if (msgfmt.found() and
2442       cc.check_header('libintl.h', required: nlsopt,
2443         args: test_c_args, include_directories: postgres_inc))
2445     # in libc
2446     if cc.has_function('ngettext')
2447       libintl = declare_dependency()
2448     else
2449       libintl = cc.find_library('intl',
2450         has_headers: ['libintl.h'], required: nlsopt,
2451         header_include_directories: postgres_inc,
2452         dirs: test_lib_d)
2453     endif
2454   endif
2456   if libintl.found()
2457     i18n = import('i18n')
2458     cdata.set('ENABLE_NLS', 1)
2459   endif
2460 endif
2464 ###############################################################
2465 # Build
2466 ###############################################################
2468 # Set up compiler / linker arguments to be used everywhere, individual targets
2469 # can add further args directly, or indirectly via dependencies
2470 add_project_arguments(cflags, language: ['c'])
2471 add_project_arguments(cppflags, language: ['c'])
2472 add_project_arguments(cflags_warn, language: ['c'])
2473 add_project_arguments(cxxflags, language: ['cpp'])
2474 add_project_arguments(cppflags, language: ['cpp'])
2475 add_project_arguments(cxxflags_warn, language: ['cpp'])
2476 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2479 # Collect a number of lists of things while recursing through the source
2480 # tree. Later steps then can use those.
2482 # list of targets for various alias targets
2483 backend_targets = []
2484 bin_targets = []
2485 pl_targets = []
2486 contrib_targets = []
2487 testprep_targets = []
2490 # Define the tests to distribute them to the correct test styles later
2491 test_deps = []
2492 tests = []
2495 # Default options for targets
2497 # First identify rpaths
2498 bin_install_rpaths = []
2499 lib_install_rpaths = []
2500 mod_install_rpaths = []
2503 # Don't add rpaths on darwin for now - as long as only absolute references to
2504 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2505 # their final destination.
2506 if host_system != 'darwin'
2507   # Add absolute path to libdir to rpath. This ensures installed binaries /
2508   # libraries find our libraries (mainly libpq).
2509   bin_install_rpaths += dir_prefix / dir_lib
2510   lib_install_rpaths += dir_prefix / dir_lib
2511   mod_install_rpaths += dir_prefix / dir_lib
2513   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2514   #
2515   # Not needed on darwin even if we use relative rpaths for our own libraries,
2516   # as the install_name of libraries in extra_lib_dirs will point to their
2517   # location anyway.
2518   bin_install_rpaths += postgres_lib_d
2519   lib_install_rpaths += postgres_lib_d
2520   mod_install_rpaths += postgres_lib_d
2521 endif
2524 # Define arguments for default targets
2526 default_target_args = {
2527   'implicit_include_directories': false,
2528   'install': true,
2531 default_lib_args = default_target_args + {
2532   'name_prefix': '',
2533   'install_rpath': ':'.join(lib_install_rpaths),
2536 internal_lib_args = default_lib_args + {
2537   'build_by_default': false,
2538   'install': false,
2541 default_mod_args = default_lib_args + {
2542   'name_prefix': '',
2543   'install_dir': dir_lib_pkg,
2544   'install_rpath': ':'.join(mod_install_rpaths),
2547 default_bin_args = default_target_args + {
2548   'install_dir': dir_bin,
2549   'install_rpath': ':'.join(bin_install_rpaths),
2554 # Helper for exporting a limited number of symbols
2555 gen_export_kwargs = {
2556   'input': 'exports.txt',
2557   'output': '@BASENAME@.'+export_file_suffix,
2558   'command': [perl, files('src/tools/gen_export.pl'),
2559    '--format', export_file_format,
2560    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2561   'build_by_default': false,
2562   'install': false,
2567 # headers that the whole build tree depends on
2568 generated_headers = []
2569 # headers that the backend build depends on
2570 generated_backend_headers = []
2571 # configure_files() output, needs a way of converting to file names
2572 configure_files = []
2574 # generated files that might conflict with a partial in-tree autoconf build
2575 generated_sources = []
2576 # same, for paths that differ between autoconf / meson builds
2577 # elements are [dir, [files]]
2578 generated_sources_ac = {}
2581 # First visit src/include - all targets creating headers are defined
2582 # within. That makes it easy to add the necessary dependencies for the
2583 # subsequent build steps.
2585 subdir('src/include')
2587 subdir('config')
2589 # Then through src/port and src/common, as most other things depend on them
2591 frontend_port_code = declare_dependency(
2592   compile_args: ['-DFRONTEND'],
2593   include_directories: [postgres_inc],
2594   dependencies: os_deps,
2597 backend_port_code = declare_dependency(
2598   compile_args: ['-DBUILDING_DLL'],
2599   include_directories: [postgres_inc],
2600   sources: [errcodes], # errcodes.h is needed due to use of ereport
2601   dependencies: os_deps,
2604 subdir('src/port')
2606 frontend_common_code = declare_dependency(
2607   compile_args: ['-DFRONTEND'],
2608   include_directories: [postgres_inc],
2609   sources: generated_headers,
2610   dependencies: [os_deps, zlib, zstd],
2613 backend_common_code = declare_dependency(
2614   compile_args: ['-DBUILDING_DLL'],
2615   include_directories: [postgres_inc],
2616   sources: generated_headers,
2617   dependencies: [os_deps, zlib, zstd],
2620 subdir('src/common')
2622 frontend_shlib_code = declare_dependency(
2623   compile_args: ['-DFRONTEND'],
2624   include_directories: [postgres_inc],
2625   link_args: ldflags_sl,
2626   link_with: [pgport_shlib, common_shlib],
2627   sources: generated_headers,
2628   dependencies: [os_deps, libintl],
2631 libpq_deps += [
2632   frontend_shlib_code,
2633   thread_dep,
2635   gssapi,
2636   ldap_r,
2637   libintl,
2638   ssl,
2641 subdir('src/interfaces/libpq')
2642 # fe_utils depends on libpq
2643 subdir('src/fe_utils')
2645 frontend_code = declare_dependency(
2646   include_directories: [postgres_inc],
2647   link_with: [fe_utils, common_static, pgport_static],
2648   sources: generated_headers,
2649   dependencies: [os_deps, libintl],
2652 backend_both_deps += [
2653   thread_dep,
2654   bsd_auth,
2655   gssapi,
2656   icu,
2657   icu_i18n,
2658   ldap,
2659   libintl,
2660   libxml,
2661   lz4,
2662   pam,
2663   ssl,
2664   systemd,
2665   zlib,
2666   zstd,
2669 backend_mod_deps = backend_both_deps + os_deps
2671 backend_code = declare_dependency(
2672   compile_args: ['-DBUILDING_DLL'],
2673   include_directories: [postgres_inc],
2674   link_args: ldflags_be,
2675   link_with: [],
2676   sources: generated_headers + generated_backend_headers,
2677   dependencies: os_deps + backend_both_deps + backend_deps,
2680 # src/backend/meson.build defines backend_mod_code used for extension
2681 # libraries.
2684 # Then through the main sources. That way contrib can have dependencies on
2685 # main sources. Note that this explicitly doesn't enter src/test, right now a
2686 # few regression tests depend on contrib files.
2688 subdir('src')
2690 subdir('contrib')
2692 subdir('src/test')
2693 subdir('src/interfaces/libpq/test')
2694 subdir('src/interfaces/ecpg/test')
2696 subdir('doc/src/sgml')
2698 generated_sources_ac += {'': ['GNUmakefile']}
2701 # If there are any files in the source directory that we also generate in the
2702 # build directory, they might get preferred over the newly generated files,
2703 # e.g. because of a #include "file", which always will search in the current
2704 # directory first.
2705 message('checking for file conflicts between source and build directory')
2706 conflicting_files = []
2707 potentially_conflicting_files_t = []
2708 potentially_conflicting_files_t += generated_headers
2709 potentially_conflicting_files_t += generated_backend_headers
2710 potentially_conflicting_files_t += generated_backend_sources
2711 potentially_conflicting_files_t += generated_sources
2713 potentially_conflicting_files = []
2715 # convert all sources of potentially conflicting files into uniform shape
2716 foreach t : potentially_conflicting_files_t
2717   potentially_conflicting_files += t.full_path()
2718 endforeach
2719 foreach t : configure_files
2720   t = '@0@'.format(t)
2721   potentially_conflicting_files += meson.current_build_dir() / t
2722 endforeach
2723 foreach sub, fnames : generated_sources_ac
2724   sub = meson.build_root() / sub
2725   foreach fname : fnames
2726     potentially_conflicting_files += sub / fname
2727   endforeach
2728 endforeach
2730 # find and report conflicting files
2731 foreach build_path : potentially_conflicting_files
2732   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2733   # str.replace is in 0.56
2734   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2735   if fs.exists(src_path) or fs.is_symlink(src_path)
2736     conflicting_files += src_path
2737   endif
2738 endforeach
2739 # XXX: Perhaps we should generate a file that would clean these up? The list
2740 # can be long.
2741 if conflicting_files.length() > 0
2742   errmsg_cleanup = '''
2743 Conflicting files in source directory:
2744   @0@
2746 The conflicting files need to be removed, either by removing the files listed
2747 above, or by running configure and then make maintainer-clean.
2749   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2750   error(errmsg_nonclean_base.format(errmsg_cleanup))
2751 endif
2755 ###############################################################
2756 # Test prep
2757 ###############################################################
2759 # DESTDIR for the installation we'll run tests in
2760 test_install_destdir = meson.build_root() / 'tmp_install/'
2762 # DESTDIR + prefix appropriately munged
2763 if build_system != 'windows'
2764   # On unixoid systems this is trivial, we just prepend the destdir
2765   assert(dir_prefix.startswith('/')) # enforced by meson
2766   test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
2767 else
2768   # drives, drive-relative paths, etc make this complicated on windows, call
2769   # meson's logic for it
2770   command = [
2771     meson_bin, meson_args, 'runpython', '-c',
2772     'import sys; from mesonbuild.scripts import destdir_join; print(destdir_join(sys.argv[4], sys.argv[5]))',
2773     test_install_destdir, dir_prefix]
2774   test_install_location = run_command(command, check: true).stdout().strip()
2775 endif
2777 meson_install_args = meson_args + ['install'] + {
2778     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
2779     'muon': []
2780 }[meson_impl]
2782 test('tmp_install',
2783     meson_bin, args: meson_install_args ,
2784     env: {'DESTDIR':test_install_destdir},
2785     priority: 100,
2786     timeout: 300,
2787     is_parallel: false,
2788     suite: ['setup'])
2790 test_result_dir = meson.build_root() / 'testrun'
2793 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
2794 # inevitable conflicts from running tests in parallel, hackishly assign
2795 # different ports for different tests.
2797 testport = 40000
2799 test_env = environment()
2801 temp_install_bindir = test_install_location / get_option('bindir')
2802 test_env.set('PG_REGRESS', pg_regress.full_path())
2803 test_env.set('REGRESS_SHLIB', regress_module.full_path())
2805 # Test suites that are not safe by default but can be run if selected
2806 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
2807 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
2808 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
2810 # Add the temporary installation to the library search path on platforms where
2811 # that works (everything but windows, basically). On windows everything
2812 # library-like gets installed into bindir, solving that issue.
2813 if library_path_var != ''
2814   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
2815 endif
2819 ###############################################################
2820 # Test Generation
2821 ###############################################################
2823 testwrap = files('src/tools/testwrap')
2825 foreach test_dir : tests
2826   testwrap_base = [
2827     testwrap,
2828     '--basedir', meson.build_root(),
2829     '--srcdir', test_dir['sd'],
2830     '--testgroup', test_dir['name'],
2831   ]
2833   foreach kind, v : test_dir
2834     if kind in ['sd', 'bd', 'name']
2835       continue
2836     endif
2838     t = test_dir[kind]
2840     if kind in ['regress', 'isolation', 'ecpg']
2841       if kind == 'regress'
2842         runner = pg_regress
2843       elif kind == 'isolation'
2844         runner = pg_isolation_regress
2845       elif kind == 'ecpg'
2846         runner = pg_regress_ecpg
2847       endif
2849       test_output = test_result_dir / test_dir['name'] / kind
2851       test_command = [
2852         runner.full_path(),
2853         '--inputdir', t.get('inputdir', test_dir['sd']),
2854         '--expecteddir', t.get('expecteddir', test_dir['sd']),
2855         '--outputdir', test_output,
2856         '--temp-instance', test_output / 'tmp_check',
2857         '--bindir', '',
2858         '--dlpath', test_dir['bd'],
2859         '--max-concurrent-tests=20',
2860         '--port', testport.to_string(),
2861       ] + t.get('regress_args', [])
2863       if t.has_key('schedule')
2864         test_command += ['--schedule', t['schedule'],]
2865       endif
2867       if kind == 'isolation'
2868         test_command += t.get('specs', [])
2869       else
2870         test_command += t.get('sql', [])
2871       endif
2873       env = test_env
2874       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
2876       test_kwargs = {
2877         'suite': [test_dir['name']],
2878         'priority': 10,
2879         'timeout': 1000,
2880         'depends': test_deps + t.get('deps', []),
2881         'env': env,
2882       } + t.get('test_kwargs', {})
2884       test(test_dir['name'] / kind,
2885         python,
2886         args: testwrap_base + [
2887           '--testname', kind,
2888           '--', test_command,
2889         ],
2890         kwargs: test_kwargs,
2891       )
2893       testport += 1
2894     elif kind == 'tap'
2895       if not tap_tests_enabled
2896         continue
2897       endif
2899       test_command = [
2900         perl.path(),
2901         '-I', meson.source_root() / 'src/test/perl',
2902         '-I', test_dir['sd'],
2903       ]
2905       # Add temporary install, the build directory for non-installed binaries and
2906       # also test/ for non-installed test binaries built separately.
2907       env = test_env
2908       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
2910       foreach name, value : t.get('env', {})
2911         env.set(name, value)
2912       endforeach
2914       test_kwargs = {
2915         'protocol': 'tap',
2916         'suite': [test_dir['name']],
2917         'timeout': 1000,
2918         'depends': test_deps + t.get('deps', []),
2919         'env': env,
2920       } + t.get('test_kwargs', {})
2922       foreach onetap : t['tests']
2923         # Make tap test names prettier, remove t/ and .pl
2924         onetap_p = onetap
2925         if onetap_p.startswith('t/')
2926           onetap_p = onetap.split('t/')[1]
2927         endif
2928         if onetap_p.endswith('.pl')
2929           onetap_p = fs.stem(onetap_p)
2930         endif
2932         test(test_dir['name'] / onetap_p,
2933           python,
2934           kwargs: test_kwargs,
2935           args: testwrap_base + [
2936             '--testname', onetap_p,
2937             '--', test_command,
2938             test_dir['sd'] / onetap,
2939           ],
2940         )
2941       endforeach
2942     else
2943       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
2944     endif
2946   endforeach # kinds of tests
2948 endforeach # directories with tests
2952 ###############################################################
2953 # Pseudo targets
2954 ###############################################################
2956 alias_target('backend', backend_targets)
2957 alias_target('bin', bin_targets + [libpq_st])
2958 alias_target('pl', pl_targets)
2959 alias_target('contrib', contrib_targets)
2960 alias_target('testprep', testprep_targets)
2964 ###############################################################
2965 # The End, The End, My Friend
2966 ###############################################################
2968 if meson.version().version_compare('>=0.57')
2970   summary(
2971     {
2972       'data block size': cdata.get('BLCKSZ'),
2973       'WAL block size': cdata.get('XLOG_BLCKSZ') / 1024,
2974       'segment size': cdata.get('RELSEG_SIZE') / 131072,
2975     },
2976     section: 'Data layout',
2977   )
2979   summary(
2980     {
2981       'host system': '@0@ @1@'.format(host_system, host_cpu),
2982       'build system': '@0@ @1@'.format(build_machine.system(),
2983                                        build_machine.cpu_family()),
2984     },
2985     section: 'System',
2986   )
2988   summary(
2989     {
2990       'linker': '@0@'.format(cc.get_linker_id()),
2991       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
2992     },
2993     section: 'Compiler',
2994   )
2996   summary(
2997     {
2998       'CPP FLAGS': ' '.join(cppflags),
2999       'C FLAGS, functional': ' '.join(cflags),
3000       'C FLAGS, warnings': ' '.join(cflags_warn),
3001       'C FLAGS, modules': ' '.join(cflags_mod),
3002       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3003       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3004     },
3005     section: 'Compiler Flags',
3006   )
3008   if llvm.found()
3009     summary(
3010       {
3011         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3012       },
3013       section: 'Compiler',
3014     )
3016     summary(
3017       {
3018         'C++ FLAGS, functional': ' '.join(cxxflags),
3019         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3020         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3021       },
3022       section: 'Compiler Flags',
3023     )
3024   endif
3026   summary(
3027     {
3028       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3029       'dtrace': dtrace,
3030     },
3031     section: 'Programs',
3032   )
3034   summary(
3035     {
3036       'bonjour': bonjour,
3037       'bsd_auth': bsd_auth,
3038       'gss': gssapi,
3039       'icu': icu,
3040       'ldap': ldap,
3041       'libxml': libxml,
3042       'libxslt': libxslt,
3043       'llvm': llvm,
3044       'lz4': lz4,
3045       'nls': libintl,
3046       'pam': pam,
3047       'plperl': perl_dep,
3048       'plpython': python3_dep,
3049       'pltcl': tcl_dep,
3050       'readline': readline,
3051       'selinux': selinux,
3052       'ssl': ssl,
3053       'systemd': systemd,
3054       'uuid': uuid,
3055       'zlib': zlib,
3056       'zstd': zstd,
3057     },
3058     section: 'External libraries',
3059   )
3061 endif