Doc: further adjust notes about pg_upgrade_output.d.
[pgsql.git] / meson.build
blob6ffae59ba03134481e9e35210917033ae97df9d1
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   ]
24 ###############################################################
25 # Basic prep
26 ###############################################################
28 fs = import('fs')
29 pkgconfig = import('pkgconfig')
31 host_system = host_machine.system()
32 host_cpu = host_machine.cpu_family()
34 cc = meson.get_compiler('c')
36 not_found_dep = dependency('', required: false)
37 thread_dep = dependency('threads')
41 ###############################################################
42 # Safety first
43 ###############################################################
45 # It's very easy to get into confusing states when the source directory
46 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
47 # refuse to build in that case.
49 # There's a more elaborate check later, that checks for conflicts around all
50 # generated files. But we can only do that much further down the line, so this
51 # quick check seems worth it. Adhering to this advice should clean up the
52 # conflict, but won't protect against somebody doing make distclean or just
53 # removing pg_config.h
54 errmsg_nonclean_base = '''
55 ****
56 Non-clean source code directory detected.
58 To build with meson the source tree may not have an in-place, ./configure
59 style, build configured. You can have both meson and ./configure style builds
60 for the same source tree by building out-of-source / VPATH with
61 configure. Alternatively use a separate check out for meson based builds.
63 @0@
64 ****'''
65 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
66   errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
67   error(errmsg_nonclean_base.format(errmsg_cleanup))
68 endif
72 ###############################################################
73 # Variables to be determined
74 ###############################################################
76 postgres_inc_d = ['src/include']
77 postgres_inc_d += get_option('extra_include_dirs')
79 postgres_lib_d = get_option('extra_lib_dirs')
81 cppflags = []
83 cflags = []
84 cxxflags = []
85 cflags_warn = []
86 cxxflags_warn = []
87 cflags_mod = []
88 cxxflags_mod = []
90 ldflags = []
91 ldflags_be = []
92 ldflags_sl = []
93 ldflags_mod = []
95 test_c_args = []
97 os_deps = []
98 backend_both_deps = []
99 backend_deps = []
100 libpq_deps = []
102 pg_sysroot = ''
104 # source of data for pg_config.h etc
105 cdata = configuration_data()
109 ###############################################################
110 # Version and other metadata
111 ###############################################################
113 pg_version = meson.project_version()
115 if pg_version.endswith('devel')
116   pg_version_arr = [pg_version.split('devel')[0], '0']
117 elif pg_version.contains('beta')
118   pg_version_arr = [pg_version.split('beta')[0], '0']
119 elif pg_version.contains('rc')
120   pg_version_arr = [pg_version.split('rc')[0], '0']
121 else
122   pg_version_arr = pg_version.split('.')
123 endif
125 pg_version_major = pg_version_arr[0].to_int()
126 pg_version_minor = pg_version_arr[1].to_int()
127 pg_version_num = (pg_version_major * 10000) + pg_version_minor
129 pg_url = 'https://www.postgresql.org/'
131 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
132 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
133 cdata.set_quoted('PACKAGE_URL', pg_url)
134 cdata.set_quoted('PACKAGE_VERSION', pg_version)
135 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
136 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
138 pg_version += get_option('extra_version')
139 cdata.set_quoted('PG_VERSION', pg_version)
140 cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by @2@-@3@'.format(
141   pg_version, build_machine.cpu_family(), cc.get_id(), cc.version()))
142 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
143 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
144 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
145 cdata.set('PG_VERSION_NUM', pg_version_num)
146 cdata.set_quoted('CONFIGURE_ARGS', '')
150 ###############################################################
151 # Basic platform specific configuration
152 ###############################################################
154 # meson's system names don't quite map to our "traditional" names. In some
155 # places we need the "traditional" name, e.g., for mapping
156 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
157 # that purpose.
158 portname = host_system
160 exesuffix = '' # overridden below where necessary
161 dlsuffix = '.so' # overridden below where necessary
162 library_path_var = 'LD_LIBRARY_PATH'
164 # Format of file to control exports from libraries, and how to pass them to
165 # the compiler. For export_fmt @0@ is the path to the file export file.
166 export_file_format = 'gnu'
167 export_file_suffix = 'list'
168 export_fmt = '-Wl,--version-script=@0@'
170 # Flags to add when linking a postgres extension, @0@ is path to
171 # the relevant object on the platform.
172 mod_link_args_fmt = []
174 memset_loop_limit = 1024
176 # Choice of shared memory and semaphore implementation
177 shmem_kind = 'sysv'
178 sema_kind = 'sysv'
180 # We implement support for some operating systems by pretending they're
181 # another. Map here, before determining system properties below
182 if host_system == 'dragonfly'
183   # apparently the most similar
184   host_system = 'netbsd'
185 endif
187 if host_system == 'aix'
188   library_path_var = 'LIBPATH'
190   export_file_format = 'aix'
191   export_fmt = '-Wl,-bE:@0@'
192   mod_link_args_fmt = ['-Wl,-bI:@0@']
193   mod_link_with_dir = 'libdir'
194   mod_link_with_name = '@0@.imp'
196   # M:SRE sets a flag indicating that an object is a shared library. Seems to
197   # work in some circumstances without, but required in others.
198   ldflags_sl += '-Wl,-bM:SRE'
199   ldflags_be += '-Wl,-brtllib'
201   # Native memset() is faster, tested on:
202   # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
203   # - AIX 5.3 ML3, gcc 4.0.1
204   memset_loop_limit = 0
206 elif host_system == 'cygwin'
207   cppflags += '-D_GNU_SOURCE'
209 elif host_system == 'darwin'
210   dlsuffix = '.dylib'
211   library_path_var = 'DYLD_LIBRARY_PATH'
213   export_file_format = 'darwin'
214   export_fmt = '-exported_symbols_list=@0@'
216   mod_link_args_fmt = ['-bundle_loader', '@0@']
217   mod_link_with_dir = 'bindir'
218   mod_link_with_name = '@0@'
220   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
221   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
222   message('darwin sysroot: @0@'.format(pg_sysroot))
223   cflags += ['-isysroot', pg_sysroot]
224   ldflags += ['-isysroot', pg_sysroot]
226 elif host_system == 'freebsd'
227   sema_kind = 'unnamed_posix'
229 elif host_system == 'linux'
230   sema_kind = 'unnamed_posix'
231   cppflags += '-D_GNU_SOURCE'
233 elif host_system == 'netbsd'
234   # We must resolve all dynamic linking in the core server at program start.
235   # Otherwise the postmaster can self-deadlock due to signals interrupting
236   # resolution of calls, since NetBSD's linker takes a lock while doing that
237   # and some postmaster signal handlers do things that will also acquire that
238   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
239   # While there's not a hard reason to adopt these settings for our other
240   # executables, there's also little reason not to, so just add them to
241   # LDFLAGS.
242   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
244 elif host_system == 'openbsd'
245   # you're ok
247 elif host_system == 'sunos'
248   portname = 'solaris'
249   export_fmt = '-Wl,-M@0@'
250   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
252 elif host_system == 'windows'
253   portname = 'win32'
254   exesuffix = '.exe'
255   dlsuffix = '.dll'
256   library_path_var = ''
258   export_file_format = 'win'
259   export_file_suffix = 'def'
260   if cc.get_id() == 'msvc'
261     export_fmt = '/DEF:@0@'
262     mod_link_with_name = '@0@.exe.lib'
263   else
264     export_fmt = '@0@'
265     mod_link_with_name = 'lib@0@.exe.a'
266   endif
267   mod_link_args_fmt = ['@0@']
268   mod_link_with_dir = 'libdir'
270   shmem_kind = 'win32'
271   sema_kind = 'win32'
273   cdata.set('WIN32_STACK_RLIMIT', 4194304)
274   if cc.get_id() == 'msvc'
275     ldflags += '/INCREMENTAL:NO'
276     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
277     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
278   else
279     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
280   endif
282   os_deps += cc.find_library('ws2_32', required: true)
283   secur32_dep = cc.find_library('secur32', required: true)
284   backend_deps += secur32_dep
285   libpq_deps += secur32_dep
287   postgres_inc_d += 'src/include/port/win32'
288   if cc.get_id() == 'msvc'
289     postgres_inc_d += 'src/include/port/win32_msvc'
290   endif
292   windows = import('windows')
294 else
295   # XXX: Should we add an option to override the host_system as an escape
296   # hatch?
297   error('unknown host system: @0@'.format(host_system))
298 endif
302 ###############################################################
303 # Program paths
304 ###############################################################
306 # External programs
307 perl = find_program(get_option('PERL'), required: true, native: true)
308 python = find_program(get_option('PYTHON'), required: true, native: true)
309 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.31')
310 bison = find_program(get_option('BISON'), native: true, version: '>= 1.875')
311 sed = find_program(get_option('SED'), 'sed', native: true)
312 prove = find_program(get_option('PROVE'), native: true)
313 tar = find_program(get_option('TAR'), native: true)
314 gzip = find_program(get_option('GZIP'), native: true)
315 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
316 touch = find_program('touch', native: true)
317 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
318 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
319 missing = find_program('config/missing', native: true)
321 # used by PGXS
322 install_sh = find_program('config/install-sh', native: true)
324 bison_flags = []
325 if bison.found()
326   bison_version_c = run_command(bison, '--version', check: true)
327   # bison version string helpfully is something like
328   # >>bison (GNU bison) 3.8.1<<
329   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
330   if bison_version.version_compare('>=3.0')
331     bison_flags += ['-Wno-deprecated']
332   endif
333 endif
334 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
335 bison_kw = {
336   'output': ['@BASENAME@.c', '@BASENAME@.h'],
337   'command': bison_cmd,
340 flex_flags = []
341 flex_wrapper = files('src/tools/pgflex')
342 flex_cmd = [python, flex_wrapper,
343   '--builddir', '@BUILD_ROOT@',
344   '--srcdir', '@SOURCE_ROOT@',
345   '--privatedir', '@PRIVATE_DIR@',
346   '--flex', flex, '--perl', perl,
347   '-i', '@INPUT@', '-o', '@OUTPUT0@',
350 wget = find_program('wget', required: false, native: true)
351 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
355 ###############################################################
356 # Path to meson (for tests etc)
357 ###############################################################
359 # NB: this should really be part of meson, see
360 # https://github.com/mesonbuild/meson/issues/8511
361 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
363 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
364   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
365     meson_binpath_r.returncode(),
366     meson_binpath_r.stdout(),
367     meson_binpath_r.stderr()))
368 endif
370 meson_binpath_s = meson_binpath_r.stdout().split('\n')
371 meson_binpath_len = meson_binpath_s.length()
373 if meson_binpath_len < 1
374   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
375 endif
377 i = 0
378 meson_impl = ''
379 meson_binpath = ''
380 meson_args = []
381 foreach e : meson_binpath_s
382   if i == 0
383     meson_impl = e
384   elif i == 1
385     meson_binpath = e
386   else
387     meson_args += e
388   endif
389   i += 1
390 endforeach
392 if meson_impl not in ['muon', 'meson']
393   error('unknown meson implementation "@0@"'.format(meson_impl))
394 endif
396 meson_bin = find_program(meson_binpath, native: true)
400 ###############################################################
401 # Option Handling
402 ###############################################################
404 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
406 cdata.set('BLCKSZ', get_option('blocksize').to_int() * 1024, description:
407 '''Size of a disk block --- this also limits the size of a tuple. You can set
408    it bigger if you need bigger tuples (although TOAST should reduce the need
409    to have large tuples, since fields can be spread across multiple tuples).
410    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
411    currently 2^15 (32768). This is determined by the 15-bit widths of the
412    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
413    Changing BLCKSZ requires an initdb.''')
415 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
416 cdata.set('RELSEG_SIZE', get_option('segsize') * 131072)
417 cdata.set('DEF_PGPORT', get_option('pgport'))
418 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
419 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
420 if get_option('system_tzdata') != ''
421   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
422 endif
426 ###############################################################
427 # Directories
428 ###############################################################
430 # These are set by the equivalent --xxxdir configure options.  We
431 # append "postgresql" to some of them, if the string does not already
432 # contain "pgsql" or "postgres", in order to avoid directory clutter.
434 pkg = 'postgresql'
436 dir_prefix = get_option('prefix')
438 dir_bin = get_option('bindir')
440 dir_data = get_option('datadir')
441 if not (dir_data.contains('pgsql') or dir_data.contains('postgres'))
442   dir_data = dir_data / pkg
443 endif
445 dir_sysconf = get_option('sysconfdir')
446 if not (dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
447   dir_sysconf = dir_sysconf / pkg
448 endif
450 dir_lib = get_option('libdir')
452 dir_lib_pkg = dir_lib
453 if not (dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
454   dir_lib_pkg = dir_lib_pkg / pkg
455 endif
457 dir_pgxs = dir_lib_pkg / 'pgxs'
459 dir_include = get_option('includedir')
461 dir_include_pkg = dir_include
462 dir_include_pkg_rel = ''
463 if not (dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
464   dir_include_pkg = dir_include_pkg / pkg
465   dir_include_pkg_rel = pkg
466 endif
468 dir_man = get_option('mandir')
470 # FIXME: These used to be separately configurable - worth adding?
471 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
472 dir_doc_html = dir_doc
474 dir_locale = get_option('localedir')
477 # Derived values
478 dir_bitcode = dir_lib_pkg / 'bitcode'
479 dir_include_internal = dir_include_pkg / 'internal'
480 dir_include_server = dir_include_pkg / 'server'
481 dir_include_extension = dir_include_server / 'extension'
482 dir_data_extension = dir_data / 'extension'
486 ###############################################################
487 # Search paths, preparation for compiler tests
489 # NB: Arguments added later are not automatically used for subsequent
490 # configuration-time checks (so they are more isolated). If they should be
491 # used, they need to be added to test_c_args as well.
492 ###############################################################
494 postgres_inc = [include_directories(postgres_inc_d)]
495 test_lib_d = postgres_lib_d
496 test_c_args = cppflags + cflags
500 ###############################################################
501 # Library: bsd-auth
502 ###############################################################
504 bsd_authopt = get_option('bsd_auth')
505 bsd_auth = not_found_dep
506 if cc.check_header('bsd_auth.h', required: bsd_authopt,
507     args: test_c_args, include_directories: postgres_inc)
508   cdata.set('USE_BSD_AUTH', 1)
509   bsd_auth = declare_dependency()
510 endif
514 ###############################################################
515 # Library: bonjour
517 # For now don't search for DNSServiceRegister in a library - only Apple's
518 # Bonjour implementation, which is always linked, works.
519 ###############################################################
521 bonjouropt = get_option('bonjour')
522 bonjour = dependency('', required : false)
523 if cc.check_header('dns_sd.h', required: bonjouropt,
524     args: test_c_args, include_directories: postgres_inc) and \
525    cc.has_function('DNSServiceRegister',
526     args: test_c_args, include_directories: postgres_inc)
527   cdata.set('USE_BONJOUR', 1)
528   bonjour = declare_dependency()
529 endif
533 ###############################################################
534 # Library: GSSAPI
535 ###############################################################
537 gssapiopt = get_option('gssapi')
538 krb_srvtab = ''
539 have_gssapi = false
540 if not gssapiopt.disabled()
541   gssapi = dependency('krb5-gssapi', required: gssapiopt)
542   have_gssapi = gssapi.found()
544   if not have_gssapi
545   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
546       args: test_c_args, include_directories: postgres_inc)
547     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
548   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
549     cdata.set('HAVE_GSSAPI_H', 1)
550   else
551     have_gssapi = false
552   endif
554   if not have_gssapi
555   elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
556       args: test_c_args, include_directories: postgres_inc)
557     cdata.set('ENABLE_GSS', 1)
559     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
560     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
561   elif gssapiopt.enabled()
562     error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
563   else
564     have_gssapi = false
565   endif
566 endif
567 if not have_gssapi
568   gssapi = not_found_dep
569 endif
573 ###############################################################
574 # Library: ldap
575 ###############################################################
577 ldapopt = get_option('ldap')
578 if host_system == 'windows'
579   ldap = cc.find_library('wldap32', required: ldapopt)
580   ldap_r = ldap
581 else
582   # macos framework dependency is buggy for ldap (one can argue whether it's
583   # Apple's or meson's fault), leading to an endless recursion with ldap.h
584   # including itself. See https://github.com/mesonbuild/meson/issues/10002
585   # Luckily we only need pkg-config support, so the workaround isn't
586   # complicated.
587   ldap = dependency('ldap', method: 'pkg-config', required: false)
588   ldap_r = ldap
590   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
591   # installed
592   if not ldap.found()
593     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
594       has_headers: 'ldap.h', header_include_directories: postgres_inc)
596     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
597     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
598     # library from a separate OpenLDAP installation).  The most reliable
599     # way to check that is to check for a function introduced in 2.5.
600     if not ldap.found()
601       # don't have ldap, we shouldn't check for ldap_r
602     elif cc.has_function('ldap_verify_credentials',
603         dependencies: ldap, args: test_c_args)
604       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
605     else
607       # Use ldap_r for FE if available, else assume ldap is thread-safe.
608       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
609         has_headers: 'ldap.h', header_include_directories: postgres_inc)
610       if not ldap_r.found()
611         ldap_r = ldap
612       else
613         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
614         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
615       endif
617       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
618       # process.  Check for OpenLDAP versions known not to tolerate doing so;
619       # assume non-OpenLDAP implementations are safe.  The dblink test suite
620       # exercises the hazardous interaction directly.
621       compat_test_code = '''
622 #include <ldap.h>
623 #if !defined(LDAP_VENDOR_VERSION) || \
624      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
625       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
626 choke me
627 #endif
629       if not cc.compiles(compat_test_code,
630           name: 'LDAP implementation compatible',
631           dependencies: ldap, args: test_c_args)
632         warning('''
633 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
634 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
635 *** also uses LDAP will crash on exit.''')
636       endif
637     endif
638   endif
640   # XXX: this shouldn't be tested in the windows case, but should be tested in
641   # the dependency() success case
642   if ldap.found() and cc.has_function('ldap_initialize',
643       dependencies: ldap, args: test_c_args)
644     cdata.set('HAVE_LDAP_INITIALIZE', 1)
645   endif
646 endif
648 if ldap.found()
649   assert(ldap_r.found())
650   cdata.set('USE_LDAP', 1)
651 else
652   assert(not ldap_r.found())
653 endif
657 ###############################################################
658 # Library: LLVM
659 ###############################################################
661 llvmopt = get_option('llvm')
662 if not llvmopt.disabled()
663   add_languages('cpp', required: true, native: false)
664   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
666   if llvm.found()
668     cdata.set('USE_LLVM', 1)
670     cpp = meson.get_compiler('cpp')
672     llvm_binpath = llvm.get_variable(configtool: 'bindir')
674     ccache = find_program('ccache', native: true, required: false)
675     clang = find_program(llvm_binpath / 'clang', required: true)
676   endif
677 else
678   llvm = not_found_dep
679 endif
683 ###############################################################
684 # Library: icu
685 ###############################################################
687 icuopt = get_option('icu')
688 if not icuopt.disabled()
689   icu = dependency('icu-uc', required: icuopt.enabled())
690   icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
692   if icu.found()
693     cdata.set('USE_ICU', 1)
694   endif
696 else
697   icu = not_found_dep
698   icu_i18n = not_found_dep
699 endif
703 ###############################################################
704 # Library: libxml
705 ###############################################################
707 libxmlopt = get_option('libxml')
708 if not libxmlopt.disabled()
709   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
711   if libxml.found()
712     cdata.set('USE_LIBXML', 1)
713   endif
714 else
715   libxml = not_found_dep
716 endif
720 ###############################################################
721 # Library: libxslt
722 ###############################################################
724 libxsltopt = get_option('libxslt')
725 if not libxsltopt.disabled()
726   libxslt = dependency('libxslt', required: libxsltopt)
728   if libxslt.found()
729     cdata.set('USE_LIBXSLT', 1)
730   endif
731 else
732   libxslt = not_found_dep
733 endif
737 ###############################################################
738 # Library: lz4
739 ###############################################################
741 lz4opt = get_option('lz4')
742 if not lz4opt.disabled()
743   lz4 = dependency('liblz4', required: lz4opt)
745   if lz4.found()
746     cdata.set('USE_LZ4', 1)
747     cdata.set('HAVE_LIBLZ4', 1)
748   endif
750 else
751   lz4 = not_found_dep
752 endif
756 ###############################################################
757 # Library: Tcl (for pltcl)
759 # NB: tclConfig.sh is used in autoconf build for getting
760 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
761 # variables. For now we have not seen a need to copy
762 # that behaviour to the meson build.
763 ###############################################################
765 tclopt = get_option('pltcl')
766 tcl_version = get_option('tcl_version')
767 tcl_dep = not_found_dep
768 if not tclopt.disabled()
770   # via pkg-config
771   tcl_dep = dependency(tcl_version, required: false)
773   if not tcl_dep.found()
774     tcl_dep = cc.find_library(tcl_version,
775       required: tclopt,
776       dirs: test_lib_d)
777   endif
779   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
780     tcl_dep = not_found_dep
781   endif
782 endif
786 ###############################################################
787 # Library: pam
788 ###############################################################
790 pamopt = get_option('pam')
791 if not pamopt.disabled()
792   pam = dependency('pam', required: false)
794   if not pam.found()
795     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
796   endif
798   if pam.found()
799     pam_header_found = false
801     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
802     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
803         args: test_c_args, include_directories: postgres_inc)
804       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
805       pam_header_found = true
806     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
807         args: test_c_args, include_directories: postgres_inc)
808       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
809       pam_header_found = true
810     endif
812     if pam_header_found
813       cdata.set('USE_PAM', 1)
814     else
815       pam = not_found_dep
816     endif
817   endif
818 else
819   pam = not_found_dep
820 endif
824 ###############################################################
825 # Library: Perl (for plperl)
826 ###############################################################
828 perlopt = get_option('plperl')
829 perl_dep = not_found_dep
830 if not perlopt.disabled()
831   perl_may_work = true
833   # First verify that perl has the necessary dependencies installed
834   perl_mods = run_command(
835     [perl,
836      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
837      '-e', ''],
838     check: false)
839   if perl_mods.returncode() != 0
840     perl_may_work = false
841     perl_msg = 'perl installation does not have the required modules'
842   endif
844   # Then inquire perl about its configuration
845   if perl_may_work
846     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
847     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
848     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
849     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
850     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
852     perl_inc_dir = '@0@/CORE'.format(archlibexp)
854     if useshrplib != 'true'
855       perl_may_work = false
856       perl_msg = 'need a shared perl'
857     endif
858   endif
860   if perl_may_work
861     # On most platforms, archlibexp is also where the Perl include files live ...
862     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
863     # ... but on newer macOS versions, we must use -iwithsysroot to look
864     # under sysroot
865     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
866        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
867       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
868     endif
870     # check compiler finds header
871     if not cc.has_header('perl.h', required: false,
872         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
873       perl_may_work = false
874       perl_msg = 'missing perl.h'
875     endif
876   endif
878   if perl_may_work
879     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
881     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
882     foreach flag : perl_ccflags_r.split(' ')
883       if flag.startswith('-D') and \
884           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
885         perl_ccflags += flag
886       endif
887     endforeach
889     if host_system == 'windows'
890       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
891     endif
893     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
894     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
896     # We are after Embed's ldopts, but without the subset mentioned in
897     # Config's ccdlflags and ldflags.  (Those are the choices of those who
898     # built the Perl installation, which are not necessarily appropriate
899     # for building PostgreSQL.)
900     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
901     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
902     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
904     perl_ldopts = []
905     foreach ldopt : ldopts.split(' ')
906       if ldopt == '' or ldopt in undesired
907         continue
908       endif
910       perl_ldopts += ldopt.strip('"')
911     endforeach
913     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
914     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
916     perl_dep_int = declare_dependency(
917       compile_args: perl_ccflags,
918       link_args: perl_ldopts,
919       version: perlversion,
920     )
922     # While we're at it, check that we can link to libperl.
923     # On most platforms, if perl.h is there then libperl.so will be too, but
924     # at this writing Debian packages them separately.
925     perl_link_test = '''
926 /* see plperl.h */
927 #ifdef _MSC_VER
928 #define __inline__ inline
929 #endif
930 #include <EXTERN.h>
931 #include <perl.h>
932 int main(void)
934 perl_alloc();
935 }'''
936     if not cc.links(perl_link_test, name: 'libperl',
937           args: test_c_args + perl_ccflags + perl_ldopts,
938           include_directories: postgres_inc)
939       perl_may_work = false
940       perl_msg = 'missing libperl'
941     endif
943   endif # perl_may_work
945   if perl_may_work
946     perl_dep = perl_dep_int
947   else
948     if perlopt.enabled()
949       error('dependency plperl failed: @0@'.format(perl_msg))
950     else
951       message('disabling optional dependency plperl: @0@'.format(perl_msg))
952     endif
953   endif
954 endif
958 ###############################################################
959 # Library: Python (for plpython)
960 ###############################################################
962 pyopt = get_option('plpython')
963 if not pyopt.disabled()
964   pm = import('python')
965   python3_inst = pm.find_installation(required: pyopt.enabled())
966   python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
967   if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
968     python3_dep = not_found_dep
969   endif
970 else
971   python3_dep = not_found_dep
972 endif
976 ###############################################################
977 # Library: Readline
978 ###############################################################
980 if not get_option('readline').disabled()
981   libedit_preferred = get_option('libedit_preferred')
982   # Set the order of readline dependencies
983   check_readline_deps = libedit_preferred ? \
984     ['libedit', 'readline'] : ['readline', 'libedit']
986   foreach readline_dep : check_readline_deps
987     readline = dependency(readline_dep, required: false)
988     if not readline.found()
989       readline = cc.find_library(readline_dep,
990         required: get_option('readline').enabled(),
991         dirs: test_lib_d)
992     endif
993     if readline.found()
994       break
995     endif
996   endforeach
998   if readline.found()
999     cdata.set('HAVE_LIBREADLINE', 1)
1001     editline_prefix = {
1002       'header_prefix': 'editline/',
1003       'flag_prefix': 'EDITLINE_',
1004     }
1005     readline_prefix = {
1006       'header_prefix': 'readline/',
1007       'flag_prefix': 'READLINE_',
1008     }
1009     default_prefix = {
1010       'header_prefix': '',
1011       'flag_prefix': '',
1012     }
1014     # Set the order of prefixes
1015     prefixes = libedit_preferred ? \
1016       [editline_prefix, default_prefix, readline_prefix] : \
1017       [readline_prefix, default_prefix, editline_prefix]
1019     at_least_one_header_found = false
1020     foreach header : ['history', 'readline']
1021       is_found = false
1022       foreach prefix : prefixes
1023         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1024         # Check history.h and readline.h
1025         if not is_found and cc.has_header(header_file,
1026             args: test_c_args, include_directories: postgres_inc,
1027             dependencies: [readline], required: false)
1028           if header == 'readline'
1029             readline_h = header_file
1030           endif
1031           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1032           is_found = true
1033           at_least_one_header_found = true
1034         endif
1035       endforeach
1036     endforeach
1038     if not at_least_one_header_found
1039       error('''readline header not found
1040 If you have @0@ already installed, see see meson-log/meson-log.txt for details on the
1041 failure. It is possible the compiler isn't looking in the proper directory.
1042 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1043     endif
1045     check_funcs = [
1046       'append_history',
1047       'history_truncate_file',
1048       'rl_completion_matches',
1049       'rl_filename_completion_function',
1050       'rl_reset_screen_size',
1051       'rl_variable_bind',
1052     ]
1054     foreach func : check_funcs
1055       found = cc.has_function(func, dependencies: [readline],
1056         args: test_c_args, include_directories: postgres_inc)
1057       cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1058     endforeach
1060     check_vars = [
1061       'rl_completion_suppress_quote',
1062       'rl_filename_quote_characters',
1063       'rl_filename_quoting_function',
1064     ]
1066     foreach var : check_vars
1067       cdata.set('HAVE_'+var.to_upper(),
1068         cc.has_header_symbol(readline_h, var,
1069           args: test_c_args, include_directories: postgres_inc,
1070           prefix: '#include <stdio.h>',
1071           dependencies: [readline]) ? 1 : false)
1072     endforeach
1074     # If found via cc.find_library() ensure headers are found when using the
1075     # dependency. On meson < 0.57 one cannot do compiler checks using the
1076     # dependency returned by declare_dependency(), so we can't do this above.
1077     if readline.type_name() == 'library'
1078       readline = declare_dependency(dependencies: readline,
1079         include_directories: postgres_inc)
1080     endif
1081   endif
1083   # XXX: Figure out whether to implement mingw warning equivalent
1084 else
1085   readline = not_found_dep
1086 endif
1090 ###############################################################
1091 # Library: selinux
1092 ###############################################################
1094 selinux = not_found_dep
1095 selinuxopt = get_option('selinux')
1096 if meson.version().version_compare('>=0.59')
1097   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1098 endif
1099 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1100 cdata.set('HAVE_LIBSELINUX',
1101   selinux.found() ? 1 : false)
1105 ###############################################################
1106 # Library: systemd
1107 ###############################################################
1109 systemd = not_found_dep
1110 systemdopt = get_option('systemd')
1111 if meson.version().version_compare('>=0.59')
1112   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1113 endif
1114 systemd = dependency('libsystemd', required: systemdopt)
1115 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1119 ###############################################################
1120 # Library: SSL
1121 ###############################################################
1123 if get_option('ssl') == 'openssl'
1125   # Try to find openssl via pkg-config et al, if that doesn't work
1126   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1127   # the library names that we know about.
1129   # via pkg-config et al
1130   ssl = dependency('openssl', required: false)
1132   # via library + headers
1133   if not ssl.found()
1134     ssl_lib = cc.find_library('ssl',
1135       dirs: test_lib_d,
1136       header_include_directories: postgres_inc,
1137       has_headers: ['openssl/ssl.h', 'openssl/err.h'])
1138     crypto_lib = cc.find_library('crypto',
1139       dirs: test_lib_d,
1140       header_include_directories: postgres_inc)
1141     ssl_int = [ssl_lib, crypto_lib]
1143     ssl = declare_dependency(dependencies: ssl_int,
1144                              include_directories: postgres_inc)
1145   else
1146     cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
1147     cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
1149     ssl_int = [ssl]
1150   endif
1152   check_funcs = [
1153     ['CRYPTO_new_ex_data', {'required': true}],
1154     ['SSL_new', {'required': true}],
1156     # Function introduced in OpenSSL 1.0.2.
1157     ['X509_get_signature_nid'],
1159     # Functions introduced in OpenSSL 1.1.0. We used to check for
1160     # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1161     # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1162     # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1163     # functions.
1164     ['OPENSSL_init_ssl'],
1165     ['BIO_get_data'],
1166     ['BIO_meth_new'],
1167     ['ASN1_STRING_get0_data'],
1168     ['HMAC_CTX_new'],
1169     ['HMAC_CTX_free'],
1171     # OpenSSL versions before 1.1.0 required setting callback functions, for
1172     # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1173     # function was removed.
1174     ['CRYPTO_lock'],
1175   ]
1177   foreach c : check_funcs
1178     func = c.get(0)
1179     val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1180     required = c.get(1, {}).get('required', false)
1181     if required and not val
1182       error('openssl function @0@ is required'.format(func))
1183     elif not required
1184       cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1185     endif
1186   endforeach
1188   cdata.set('USE_OPENSSL', 1,
1189             description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1190   cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1191             description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1192 else
1193   ssl = not_found_dep
1194 endif
1198 ###############################################################
1199 # Library: uuid
1200 ###############################################################
1202 uuidopt = get_option('uuid')
1203 if uuidopt != 'none'
1204   uuidname = uuidopt.to_upper()
1205   if uuidopt == 'e2fs'
1206     uuid = dependency('uuid', required: true)
1207     uuidfunc = 'uuid_generate'
1208     uuidheader = 'uuid/uuid.h'
1209   elif uuidopt == 'bsd'
1210     # libc should have uuid function
1211     uuid = declare_dependency()
1212     uuidfunc = 'uuid_to_string'
1213     uuidheader = 'uuid.h'
1214   elif uuidopt == 'ossp'
1215     uuid = dependency('ossp-uuid', required: true)
1216     uuidfunc = 'uuid_export'
1217     uuidheader = 'ossp/uuid.h'
1218   else
1219     error('huh')
1220   endif
1222   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1223     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1224   endif
1225   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1227   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1228            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1229 else
1230   uuid = not_found_dep
1231 endif
1235 ###############################################################
1236 # Library: zlib
1237 ###############################################################
1239 zlibopt = get_option('zlib')
1240 zlib = not_found_dep
1241 if not zlibopt.disabled()
1242   zlib_t = dependency('zlib', required: zlibopt)
1244   if zlib_t.type_name() == 'internal'
1245     # if fallback was used, we don't need to test if headers are present (they
1246     # aren't built yet, so we can't test)
1247     zlib = zlib_t
1248   elif not zlib_t.found()
1249     warning('did not find zlib')
1250   elif not cc.has_header('zlib.h',
1251       args: test_c_args, include_directories: postgres_inc,
1252       dependencies: [zlib_t], required: zlibopt.enabled())
1253     warning('zlib header not found')
1254   elif not cc.has_type('z_streamp',
1255       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1256       args: test_c_args, include_directories: postgres_inc)
1257     if zlibopt.enabled()
1258       error('zlib version is too old')
1259     else
1260       warning('zlib version is too old')
1261     endif
1262   else
1263     zlib = zlib_t
1264   endif
1266   if zlib.found()
1267     cdata.set('HAVE_LIBZ', 1)
1268   endif
1269 endif
1273 ###############################################################
1274 # Library: tap test dependencies
1275 ###############################################################
1277 # Check whether tap tests are enabled or not
1278 tap_tests_enabled = false
1279 tapopt = get_option('tap_tests')
1280 if not tapopt.disabled()
1281   # Checking for perl modules for tap tests
1282   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1283   if perl_ipc_run_check.returncode() != 0
1284     message(perl_ipc_run_check.stderr().strip())
1285     if tapopt.enabled()
1286       error('Additional Perl modules are required to run TAP tests.')
1287     else
1288       warning('Additional Perl modules are required to run TAP tests.')
1289     endif
1290   else
1291     tap_tests_enabled = true
1292   endif
1293 endif
1297 ###############################################################
1298 # Library: zstd
1299 ###############################################################
1301 zstdopt = get_option('zstd')
1302 if not zstdopt.disabled()
1303   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1305   if zstd.found()
1306     cdata.set('USE_ZSTD', 1)
1307     cdata.set('HAVE_LIBZSTD', 1)
1308   endif
1310 else
1311   zstd = not_found_dep
1312 endif
1316 ###############################################################
1317 # Compiler tests
1318 ###############################################################
1320 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1321 # unnecessarily, because we optionally rely on newer features.
1322 c99_test = '''
1323 #include <stdbool.h>
1324 #include <complex.h>
1325 #include <tgmath.h>
1326 #include <inttypes.h>
1328 struct named_init_test {
1329   int a;
1330   int b;
1333 extern void structfunc(struct named_init_test);
1335 int main(int argc, char **argv)
1337   struct named_init_test nit = {
1338     .a = 3,
1339     .b = 5,
1340   };
1342   for (int loop_var = 0; loop_var < 3; loop_var++)
1343   {
1344     nit.a += nit.b;
1345   }
1347   structfunc((struct named_init_test){1, 0});
1349   return nit.a != 0;
1353 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1354   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1355         args: test_c_args + ['-std=c99'])
1356     test_c_args += '-std=c99'
1357     cflags += '-std=c99'
1358   else
1359     error('C compiler does not support C99')
1360   endif
1361 endif
1363 sizeof_long = cc.sizeof('long', args: test_c_args)
1364 cdata.set('SIZEOF_LONG', sizeof_long)
1365 if sizeof_long == 8
1366   cdata.set('HAVE_LONG_INT_64', 1)
1367   cdata.set('PG_INT64_TYPE', 'long int')
1368   cdata.set_quoted('INT64_MODIFIER', 'l')
1369 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1370   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1371   cdata.set('PG_INT64_TYPE', 'long long int')
1372   cdata.set_quoted('INT64_MODIFIER', 'll')
1373 else
1374   error('do not know how to get a 64bit int')
1375 endif
1377 if host_machine.endian() == 'big'
1378   cdata.set('WORDS_BIGENDIAN', 1)
1379 endif
1381 alignof_types = ['short', 'int', 'long', 'double']
1382 maxalign = 0
1383 foreach t : alignof_types
1384   align = cc.alignment(t, args: test_c_args)
1385   if maxalign < align
1386     maxalign = align
1387   endif
1388   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1389 endforeach
1390 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1392 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1393 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1396 # Check if __int128 is a working 128 bit integer type, and if so
1397 # define PG_INT128_TYPE to that typename.
1399 # This currently only detects a GCC/clang extension, but support for other
1400 # environments may be added in the future.
1402 # For the moment we only test for support for 128bit math; support for
1403 # 128bit literals and snprintf is not required.
1404 if cc.links('''
1405   /*
1406    * We don't actually run this test, just link it to verify that any support
1407    * functions needed for __int128 are present.
1408    *
1409    * These are globals to discourage the compiler from folding all the
1410    * arithmetic tests down to compile-time constants.  We do not have
1411    * convenient support for 128bit literals at this point...
1412    */
1413   __int128 a = 48828125;
1414   __int128 b = 97656250;
1416   int main(void)
1417   {
1418       __int128 c,d;
1419       a = (a << 12) + 1; /* 200000000001 */
1420       b = (b << 12) + 5; /* 400000000005 */
1421       /* try the most relevant arithmetic ops */
1422       c = a * b;
1423       d = (c + b) / b;
1424       /* must use the results, else compiler may optimize arithmetic away */
1425       return d != a+1;
1426   }''',
1427   name: '__int128',
1428   args: test_c_args)
1430   buggy_int128 = false
1432   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1433   # If not cross-compiling, we can test for bugs and disable use of __int128
1434   # with buggy compilers.  If cross-compiling, hope for the best.
1435   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1436   if not meson.is_cross_build()
1437     r = cc.run('''
1438     /* This must match the corresponding code in c.h: */
1439     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1440     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1441     #endif
1442     typedef __int128 int128a
1443     #if defined(pg_attribute_aligned)
1444     pg_attribute_aligned(8)
1445     #endif
1446     ;
1448     int128a holder;
1449     void pass_by_val(void *buffer, int128a par) { holder = par; }
1451     int main(void)
1452     {
1453         long int i64 = 97656225L << 12;
1454         int128a q;
1455         pass_by_val(main, (int128a) i64);
1456         q = (int128a) i64;
1457         return q != holder;
1458     }''',
1459     name: '__int128 alignment bug',
1460     args: test_c_args)
1461     assert(r.compiled())
1462     if r.returncode() != 0
1463       buggy_int128 = true
1464       message('__int128 support present but buggy and thus disabled')
1465     endif
1466   endif
1468   if not buggy_int128
1469     cdata.set('PG_INT128_TYPE', '__int128')
1470     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1471       alignment('__int128', args: test_c_args))
1472   endif
1473 endif
1476 # Check if the C compiler knows computed gotos (gcc extension, also
1477 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1479 # Checking whether computed gotos are supported syntax-wise ought to
1480 # be enough, as the syntax is otherwise illegal.
1481 if cc.compiles('''
1482     static inline int foo(void)
1483     {
1484       void *labeladdrs[] = {&&my_label};
1485       goto *labeladdrs[0];
1486       my_label:
1487       return 1;
1488     }''',
1489     args: test_c_args)
1490   cdata.set('HAVE_COMPUTED_GOTO', 1)
1491 endif
1494 # Check if the C compiler understands _Static_assert(),
1495 # and define HAVE__STATIC_ASSERT if so.
1497 # We actually check the syntax ({ _Static_assert(...) }), because we need
1498 # gcc-style compound expressions to be able to wrap the thing into macros.
1499 if cc.compiles('''
1500     int main(int arg, char **argv)
1501     {
1502         ({ _Static_assert(1, "foo"); });
1503     }
1504     ''',
1505     args: test_c_args)
1506   cdata.set('HAVE__STATIC_ASSERT', 1)
1507 endif
1510 # We use <stdbool.h> if we have it and it declares type bool as having
1511 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1512 if cc.has_type('_Bool', args: test_c_args) \
1513   and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1514   and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1515   cdata.set('HAVE__BOOL', 1)
1516   cdata.set('PG_USE_STDBOOL', 1)
1517 endif
1520 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1521 # warning for each use of %m.
1522 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1523 testsrc = '''
1524 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1525 static void call_log(void)
1527     emit_log(0, "error: %s: %m", "foo");
1530 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1531 foreach a : printf_attributes
1532   if cc.compiles(testsrc.format(a),
1533       args: test_c_args + attrib_error_args, name: 'format ' + a)
1534     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1535     break
1536   endif
1537 endforeach
1540 if cc.has_function_attribute('visibility:default') and \
1541   cc.has_function_attribute('visibility:hidden')
1542   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1544   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1545   # inlineshidden to C code as well... Any either way, we want to put these
1546   # flags into exported files (pgxs, .pc files).
1547   cflags_mod += '-fvisibility=hidden'
1548   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1549   ldflags_mod += '-fvisibility=hidden'
1550 endif
1553 # Check if various builtins exist. Some builtins are tested separately,
1554 # because we want to test something more complicated than the generic case.
1555 builtins = [
1556   'bswap16',
1557   'bswap32',
1558   'bswap64',
1559   'clz',
1560   'ctz',
1561   'constant_p',
1562   'frame_address',
1563   'popcount',
1564   'unreachable',
1567 foreach builtin : builtins
1568   fname = '__builtin_@0@'.format(builtin)
1569   if cc.has_function(fname, args: test_c_args)
1570     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1571   endif
1572 endforeach
1575 # Check if the C compiler understands __builtin_types_compatible_p,
1576 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1578 # We check usage with __typeof__, though it's unlikely any compiler would
1579 # have the former and not the latter.
1580 if cc.compiles('''
1581     static int x;
1582     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1583     ''',
1584     name: '__builtin_types_compatible_p',
1585     args: test_c_args)
1586   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1587 endif
1590 # Check if the C compiler understands __builtin_$op_overflow(),
1591 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1593 # Check for the most complicated case, 64 bit multiplication, as a
1594 # proxy for all of the operations.  To detect the case where the compiler
1595 # knows the function but library support is missing, we must link not just
1596 # compile, and store the results in global variables so the compiler doesn't
1597 # optimize away the call.
1598 if cc.links('''
1599     INT64 a = 1;
1600     INT64 b = 1;
1601     INT64 result;
1603     int main(void)
1604     {
1605         return __builtin_mul_overflow(a, b, &result);
1606     }''',
1607     name: '__builtin_mul_overflow',
1608     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1609     )
1610   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1611 endif
1614 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1615 # here. To prevent problems due to two detection methods working, stop
1616 # checking after one.
1617 if cc.links('''
1618     #include <cpuid.h>
1619     int main(int arg, char **argv)
1620     {
1621         unsigned int exx[4] = {0, 0, 0, 0};
1622         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1623     }
1624     ''', name: '__get_cpuid',
1625     args: test_c_args)
1626   cdata.set('HAVE__GET_CPUID', 1)
1627 elif cc.links('''
1628     #include <intrin.h>
1629     int main(int arg, char **argv)
1630     {
1631         unsigned int exx[4] = {0, 0, 0, 0};
1632         __cpuid(exx, 1);
1633     }
1634     ''', name: '__cpuid',
1635     args: test_c_args)
1636   cdata.set('HAVE__CPUID', 1)
1637 endif
1640 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1641 # versions of clang do not understand -fexcess-precision=standard, the use of
1642 # x87 floating point operations leads to problems like isinf possibly returning
1643 # false for a value that is infinite when converted from the 80bit register to
1644 # the 8byte memory representation.
1646 # Only perform the test if the compiler doesn't understand
1647 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1648 # automatically.
1649 if '-fexcess-precision=standard' not in cflags
1650   if not cc.compiles('''
1651 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1652 choke me
1653 #endif''',
1654       name: '', args: test_c_args)
1655     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1656   endif
1657 endif
1661 ###############################################################
1662 # Compiler flags
1663 ###############################################################
1665 common_functional_flags = [
1666   # Disable strict-aliasing rules; needed for gcc 3.3+
1667   '-fno-strict-aliasing',
1668   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1669   '-fwrapv',
1670   '-fexcess-precision=standard',
1673 cflags += cc.get_supported_arguments(common_functional_flags)
1674 if llvm.found()
1675   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1676 endif
1678 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1679 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1681 common_warning_flags = [
1682   '-Wmissing-prototypes',
1683   '-Wpointer-arith',
1684   # Really don't want VLAs to be used in our dialect of C
1685   '-Werror=vla',
1686   # On macOS, complain about usage of symbols newer than the deployment target
1687   '-Werror=unguarded-availability-new',
1688   '-Wendif-labels',
1689   '-Wmissing-format-attribute',
1690   '-Wimplicit-fallthrough=3',
1691   '-Wcast-function-type',
1692   # This was included in -Wall/-Wformat in older GCC versions
1693   '-Wformat-security',
1696 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1697 if llvm.found()
1698   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1699 endif
1701 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1702 # the result for them
1703 if cc.has_argument('-Wdeclaration-after-statement')
1704   cflags_warn += '-Wdeclaration-after-statement'
1705   using_declaration_after_statement_warning = true
1706 else
1707   using_declaration_after_statement_warning = false
1708 endif
1711 # The following tests want to suppress various unhelpful warnings by adding
1712 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1713 # switches, so we have to test for the positive form and if that works,
1714 # add the negative form.
1716 negative_warning_flags = [
1717   # Suppress clang's unhelpful unused-command-line-argument warnings.
1718   'unused-command-line-argument',
1720   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1721   # of warnings when building plperl because of usages in the Perl headers.
1722   'compound-token-split-by-macro',
1724   # Similarly disable useless truncation warnings from gcc 8+
1725   'format-truncation',
1726   'stringop-truncation',
1728   # To make warning_level=2 / -Wextra work, we'd need at least the following
1729   # 'clobbered',
1730   # 'missing-field-initializers',
1731   # 'sign-compare',
1732   # 'unused-parameter',
1735 foreach w : negative_warning_flags
1736   if cc.has_argument('-W' + w)
1737     cflags_warn += '-Wno-' + w
1738   endif
1739   if llvm.found() and cpp.has_argument('-W' + w)
1740     cxxflags_warn += '-Wno-' + w
1741   endif
1742 endforeach
1745 # From Project.pm
1746 if cc.get_id() == 'msvc'
1747   cflags_warn += [
1748     '/wd4018', # signed/unsigned mismatch
1749     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1750     '/wd4273', # inconsistent DLL linkage
1751     '/wd4101', # unreferenced local variable
1752     '/wd4102', # unreferenced label
1753     '/wd4090', # different 'modifier' qualifiers
1754     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1755   ]
1757   cppflags += [
1758     '/DWIN32',
1759     '/DWINDOWS',
1760     '/D__WINDOWS__',
1761     '/D__WIN32__',
1762     '/D_CRT_SECURE_NO_DEPRECATE',
1763     '/D_CRT_NONSTDC_NO_DEPRECATE',
1764   ]
1766   # We never need export libraries. As link.exe reports their creation, they
1767   # are unnecessarily noisy. Similarly, we don't need import library for
1768   # modules, we only import them dynamically, and they're also noisy.
1769   ldflags += '/NOEXP'
1770   ldflags_mod += '/NOIMPLIB'
1771 endif
1775 ###############################################################
1776 # Atomics
1777 ###############################################################
1779 if not get_option('spinlocks')
1780   warning('Not using spinlocks will cause poor performance')
1781 else
1782   cdata.set('HAVE_SPINLOCKS', 1)
1783 endif
1785 if not get_option('atomics')
1786   warning('Not using atomics will cause poor performance')
1787 else
1788   # XXX: perhaps we should require some atomics support in this case these
1789   # days?
1790   cdata.set('HAVE_ATOMICS', 1)
1792   atomic_checks = [
1793     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1794      'desc': '__sync_lock_test_and_set(char)',
1795      'test': '''
1796 char lock = 0;
1797 __sync_lock_test_and_set(&lock, 1);
1798 __sync_lock_release(&lock);'''},
1800     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1801      'desc': '__sync_lock_test_and_set(int32)',
1802      'test': '''
1803 int lock = 0;
1804 __sync_lock_test_and_set(&lock, 1);
1805 __sync_lock_release(&lock);'''},
1807     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1808      'desc': '__sync_val_compare_and_swap(int32)',
1809      'test': '''
1810 int val = 0;
1811 __sync_val_compare_and_swap(&val, 0, 37);'''},
1813     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1814      'desc': '__sync_val_compare_and_swap(int64)',
1815      'test': '''
1816 INT64 val = 0;
1817 __sync_val_compare_and_swap(&val, 0, 37);'''},
1819     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1820      'desc': ' __atomic_compare_exchange_n(int32)',
1821      'test': '''
1822 int val = 0;
1823 int expect = 0;
1824 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1826     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1827      'desc': ' __atomic_compare_exchange_n(int64)',
1828      'test': '''
1829 INT64 val = 0;
1830 INT64 expect = 0;
1831 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1832   ]
1834   foreach check : atomic_checks
1835     test = '''
1836 int main(void)
1839 }'''.format(check['test'])
1841     cdata.set(check['name'],
1842       cc.links(test,
1843         name: check['desc'],
1844         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1845     )
1846   endforeach
1848 endif
1852 ###############################################################
1853 # Select CRC-32C implementation.
1855 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1856 # use the special CRC instructions for calculating CRC-32C. If we're not
1857 # targeting such a processor, but we can nevertheless produce code that uses
1858 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1859 # implementations and select which one to use at runtime, depending on whether
1860 # SSE 4.2 is supported by the processor we're running on.
1862 # Similarly, if we are targeting an ARM processor that has the CRC
1863 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1864 # we're not targeting such a processor, but can nevertheless produce code that
1865 # uses the CRC instructions, compile both, and select at runtime.
1866 ###############################################################
1868 have_optimized_crc = false
1869 cflags_crc = []
1870 if host_cpu == 'x86' or host_cpu == 'x86_64'
1872   if cc.get_id() == 'msvc'
1873     cdata.set('USE_SSE42_CRC32C', false)
1874     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1875     have_optimized_crc = true
1876   else
1878     prog = '''
1879 #include <nmmintrin.h>
1881 int main(void)
1883     unsigned int crc = 0;
1884     crc = _mm_crc32_u8(crc, 0);
1885     crc = _mm_crc32_u32(crc, 0);
1886     /* return computed value, to prevent the above being optimized away */
1887     return crc == 0;
1891     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
1892           args: test_c_args)
1893       # Use Intel SSE 4.2 unconditionally.
1894       cdata.set('USE_SSE42_CRC32C', 1)
1895       have_optimized_crc = true
1896     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
1897           args: test_c_args + ['-msse4.2'])
1898       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
1899       # the runtime check.
1900       cflags_crc += '-msse4.2'
1901       cdata.set('USE_SSE42_CRC32C', false)
1902       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1903       have_optimized_crc = true
1904     endif
1906   endif
1908 elif host_cpu == 'arm' or host_cpu == 'aarch64'
1910   prog = '''
1911 #include <arm_acle.h>
1913 int main(void)
1915     unsigned int crc = 0;
1916     crc = __crc32cb(crc, 0);
1917     crc = __crc32ch(crc, 0);
1918     crc = __crc32cw(crc, 0);
1919     crc = __crc32cd(crc, 0);
1921     /* return computed value, to prevent the above being optimized away */
1922     return crc == 0;
1926   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
1927       args: test_c_args)
1928     # Use ARM CRC Extension unconditionally
1929     cdata.set('USE_ARMV8_CRC32C', 1)
1930     have_optimized_crc = true
1931   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
1932       args: test_c_args + ['-march=armv8-a+crc'])
1933     # Use ARM CRC Extension, with runtime check
1934     cflags_crc += '-march=armv8-a+crc'
1935     cdata.set('USE_ARMV8_CRC32C', false)
1936     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
1937     have_optimized_crc = true
1938   endif
1939 endif
1941 if not have_optimized_crc
1942   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
1943   # support.
1944   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
1945 endif
1949 ###############################################################
1950 # Other CPU specific stuff
1951 ###############################################################
1953 if host_cpu == 'x86_64'
1955   if cc.compiles('''
1956       void main(void)
1957       {
1958           long long x = 1; long long r;
1959           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
1960       }''',
1961       name: '@0@: popcntq instruction'.format(host_cpu),
1962       args: test_c_args)
1963     cdata.set('HAVE_X86_64_POPCNTQ', 1)
1964   endif
1966 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
1967   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
1968   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
1969     if cc.compiles('''
1970       static inline int
1971       addi(int ra, int si)
1972       {
1973           int res = 0;
1974           if (__builtin_constant_p(si))
1975               __asm__ __volatile__(
1976                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
1977           return res;
1978       }
1979       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
1980       ''',
1981       args: test_c_args)
1982       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
1983     endif
1984   endif
1985 endif
1989 ###############################################################
1990 # Library / OS tests
1991 ###############################################################
1993 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
1994 # unnecessary checks over and over, particularly on windows.
1995 header_checks = [
1996   'atomic.h',
1997   'copyfile.h',
1998   'crtdefs.h',
1999   'execinfo.h',
2000   'getopt.h',
2001   'ifaddrs.h',
2002   'langinfo.h',
2003   'mbarrier.h',
2004   'stdbool.h',
2005   'strings.h',
2006   'sys/epoll.h',
2007   'sys/event.h',
2008   'sys/personality.h',
2009   'sys/prctl.h',
2010   'sys/procctl.h',
2011   'sys/signalfd.h',
2012   'sys/ucred.h',
2013   'termios.h',
2014   'ucred.h',
2017 foreach header : header_checks
2018   varname = 'HAVE_' + header.underscorify().to_upper()
2020   # Emulate autoconf behaviour of not-found->undef, found->1
2021   found = cc.has_header(header,
2022     include_directories: postgres_inc, args: test_c_args)
2023   cdata.set(varname, found ? 1 : false,
2024             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2025 endforeach
2028 decl_checks = [
2029   ['F_FULLFSYNC', 'fcntl.h'],
2030   ['fdatasync', 'unistd.h'],
2031   ['posix_fadvise', 'fcntl.h'],
2032   ['strlcat', 'string.h'],
2033   ['strlcpy', 'string.h'],
2034   ['strnlen', 'string.h'],
2037 # Need to check for function declarations for these functions, because
2038 # checking for library symbols wouldn't handle deployment target
2039 # restrictions on macOS
2040 decl_checks += [
2041   ['preadv', 'sys/uio.h'],
2042   ['pwritev', 'sys/uio.h'],
2045 foreach c : decl_checks
2046   func = c.get(0)
2047   header = c.get(1)
2048   args = c.get(2, {})
2049   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2051   found = cc.has_header_symbol(header, func,
2052     args: test_c_args, include_directories: postgres_inc,
2053     kwargs: args)
2054   cdata.set10(varname, found, description:
2055 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2056    don't.'''.format(func))
2057 endforeach
2060 if cc.has_type('struct cmsgcred',
2061     args: test_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? '' : '-DHAVE_SYS_UCRED_H'],
2062     include_directories: postgres_inc,
2063     prefix: '''
2064 #include <sys/socket.h>
2065 #include <sys/param.h>
2066 #ifdef HAVE_SYS_UCRED_H
2067 #include <sys/ucred.h>
2068 #endif''')
2069   cdata.set('HAVE_STRUCT_CMSGCRED', 1)
2070 else
2071   cdata.set('HAVE_STRUCT_CMSGCRED', false)
2072 endif
2074 if cc.has_type('struct option',
2075     args: test_c_args, include_directories: postgres_inc,
2076     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2077   cdata.set('HAVE_STRUCT_OPTION', 1)
2078 endif
2081 foreach c : ['opterr', 'optreset']
2082   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2084   if cc.links('''
2085 #include <unistd.h>
2086 int main(void)
2088     extern int @0@;
2089     @0@ = 1;
2091 '''.format(c), name: c, args: test_c_args)
2092     cdata.set(varname, 1)
2093   else
2094     cdata.set(varname, false)
2095   endif
2096 endforeach
2098 if cc.has_type('socklen_t',
2099     args: test_c_args, include_directories: postgres_inc,
2100     prefix: '''
2101 #include <sys/socket.h>''')
2102   cdata.set('HAVE_SOCKLEN_T', 1)
2103 endif
2105 if cc.has_member('struct sockaddr', 'sa_len',
2106     args: test_c_args, include_directories: postgres_inc,
2107     prefix: '''
2108 #include <sys/types.h>
2109 #include <sys/socket.h>''')
2110   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2111 endif
2113 if cc.has_member('struct tm', 'tm_zone',
2114     args: test_c_args, include_directories: postgres_inc,
2115     prefix: '''
2116 #include <sys/types.h>
2117 #include <time.h>
2118 ''')
2119   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2120 endif
2122 if cc.compiles('''
2123 #include <time.h>
2124 extern int foo(void);
2125 int foo(void)
2127     return timezone / 60;
2129 ''',
2130     name: 'global variable `timezone\' exists',
2131     args: test_c_args, include_directories: postgres_inc)
2132   cdata.set('HAVE_INT_TIMEZONE', 1)
2133 else
2134   cdata.set('HAVE_INT_TIMEZONE', false)
2135 endif
2137 if cc.has_type('union semun',
2138     args: test_c_args,
2139     include_directories: postgres_inc,
2140     prefix: '''
2141 #include <sys/types.h>
2142 #include <sys/ipc.h>
2143 #include <sys/sem.h>
2144 ''')
2145   cdata.set('HAVE_UNION_SEMUN', 1)
2146 endif
2148 if cc.compiles('''
2149 #include <string.h>
2150 int main(void)
2152   char buf[100];
2153   switch (strerror_r(1, buf, sizeof(buf)))
2154   { case 0: break; default: break; }
2155 }''',
2156     name: 'strerror_r',
2157     args: test_c_args, include_directories: postgres_inc)
2158   cdata.set('STRERROR_R_INT', 1)
2159 else
2160   cdata.set('STRERROR_R_INT', false)
2161 endif
2163 # Check for the locale_t type and find the right header file.  macOS
2164 # needs xlocale.h; standard is locale.h, but glibc also has an
2165 # xlocale.h file that we should not use.
2166 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2167   cdata.set('HAVE_LOCALE_T', 1)
2168 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2169   cdata.set('HAVE_LOCALE_T', 1)
2170   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2171 endif
2173 # Check if the C compiler understands typeof or a variant.  Define
2174 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2175 foreach kw : ['typeof', '__typeof__', 'decltype']
2176   if cc.compiles('''
2177 int main(void)
2179     int x = 0;
2180     @0@(x) y;
2181     y = x;
2182     return y;
2184 '''.format(kw),
2185     name: 'typeof()',
2186     args: test_c_args, include_directories: postgres_inc)
2188     cdata.set('HAVE_TYPEOF', 1)
2189     if kw != 'typeof'
2190       cdata.set('typeof', kw)
2191     endif
2193     break
2194   endif
2195 endforeach
2198 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2199 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2200 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2201 wcstombs_l_test = '''
2202 #include <stdlib.h>
2203 #include <locale.h>
2206 void main(void)
2208 #ifndef wcstombs_l
2209     (void) wcstombs_l;
2210 #endif
2213 if (not cc.compiles(wcstombs_l_test.format(''),
2214       name: 'wcstombs_l') and
2215     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2216       name: 'wcstombs_l in xlocale.h'))
2217     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2218 endif
2221 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2222 # understands, because it conflicts with __declspec(restrict). Therefore we
2223 # define pg_restrict to the appropriate definition, which presumably won't
2224 # conflict.
2226 # We assume C99 support, so we don't need to make this conditional.
2228 # XXX: Historically we allowed platforms to disable restrict in template
2229 # files, but that was only added for AIX when building with XLC, which we
2230 # don't support yet.
2231 cdata.set('pg_restrict', '__restrict')
2234 if cc.links('''
2235 #include <machine/vmparam.h>
2236 #include <sys/exec.h>
2238 int main(void)
2240     PS_STRINGS->ps_nargvstr = 1;
2241     PS_STRINGS->ps_argvstr = "foo";
2243 ''',
2244   name: 'PS_STRINGS', args: test_c_args)
2245   cdata.set('HAVE_PS_STRINGS', 1)
2246 else
2247   cdata.set('HAVE_PS_STRINGS', false)
2248 endif
2251 # Most libraries are included only if they demonstrably provide a function we
2252 # need, but libm is an exception: always include it, because there are too
2253 # many compilers that play cute optimization games that will break probes for
2254 # standard functions such as pow().
2255 os_deps += cc.find_library('m', required: false)
2257 rt_dep = cc.find_library('rt', required: false)
2259 dl_dep = cc.find_library('dl', required: false)
2261 util_dep = cc.find_library('util', required: false)
2262 posix4_dep = cc.find_library('posix4', required: false)
2264 getopt_dep = cc.find_library('getopt', required: false)
2265 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2267 # Required on BSDs
2268 execinfo_dep = cc.find_library('execinfo', required: false)
2270 if host_system == 'cygwin'
2271   cygipc_dep = cc.find_library('cygipc', required: false)
2272 else
2273   cygipc_dep = not_found_dep
2274 endif
2276 if host_system == 'sunos'
2277   socket_dep = cc.find_library('socket', required: false)
2278 else
2279   socket_dep = not_found_dep
2280 endif
2282 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2283 # unnecessary checks over and over, particularly on windows.
2284 func_checks = [
2285   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2286   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2287   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2288   ['copyfile'],
2289   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2290   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2291   # required. Just checking for dlsym() ought to suffice.
2292   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2293   ['explicit_bzero'],
2294   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2295   ['getifaddrs'],
2296   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep]}],
2297   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep]}],
2298   ['getpeereid'],
2299   ['getpeerucred'],
2300   ['inet_aton'],
2301   ['inet_pton'],
2302   ['kqueue'],
2303   ['mbstowcs_l'],
2304   ['memset_s'],
2305   ['mkdtemp'],
2306   ['posix_fadvise'],
2307   ['posix_fallocate'],
2308   ['ppoll'],
2309   ['pstat'],
2310   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2311   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2312   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2313   ['setproctitle', {'dependencies': [util_dep]}],
2314   ['setproctitle_fast'],
2315   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2316   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2317   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2318   ['socket', {'dependencies': [socket_dep], 'define': false}],
2319   ['strchrnul'],
2320   ['strerror_r', {'dependencies': [thread_dep]}],
2321   ['strlcat'],
2322   ['strlcpy'],
2323   ['strnlen'],
2324   ['strsignal'],
2325   ['sync_file_range'],
2326   ['syncfs'],
2327   ['uselocale'],
2328   ['wcstombs_l'],
2331 func_check_results = {}
2332 foreach c : func_checks
2333   func = c.get(0)
2334   kwargs = c.get(1, {})
2335   deps = kwargs.get('dependencies', [])
2337   if kwargs.get('skip', false)
2338     continue
2339   endif
2341   found = cc.has_function(func, args: test_c_args)
2343   if not found
2344     foreach dep : deps
2345       if not dep.found()
2346         continue
2347       endif
2348       found = cc.has_function(func, args: test_c_args,
2349                               dependencies: [dep])
2350       if found
2351         os_deps += dep
2352         break
2353       endif
2354     endforeach
2355   endif
2357   func_check_results += {func: found}
2359   if kwargs.get('define', true)
2360     # Emulate autoconf behaviour of not-found->undef, found->1
2361     cdata.set('HAVE_' + func.underscorify().to_upper(),
2362               found  ? 1 : false,
2363               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2364   endif
2365 endforeach
2368 if cc.has_function('syslog', args: test_c_args) and \
2369     cc.check_header('syslog.h', args: test_c_args)
2370   cdata.set('HAVE_SYSLOG', 1)
2371 endif
2374 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2375 # semaphores
2376 if sema_kind == 'unnamed_posix' and \
2377    not func_check_results.get('sem_init', false)
2378   sema_kind = 'sysv'
2379 endif
2381 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2382 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2384 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2385 cdata.set_quoted('DLSUFFIX', dlsuffix)
2389 ###############################################################
2390 # Threading
2391 ###############################################################
2393 # XXX: About to rely on thread safety in the autoconf build, so not worth
2394 # implementing a fallback.
2395 cdata.set('ENABLE_THREAD_SAFETY', 1)
2399 ###############################################################
2400 # NLS / Gettext
2401 ###############################################################
2403 nlsopt = get_option('nls')
2404 libintl = not_found_dep
2406 if not nlsopt.disabled()
2407   # otherwise there'd be lots of
2408   # "Gettext not found, all translation (po) targets will be ignored."
2409   # warnings if not found.
2410   msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2412   # meson 0.59 has this wrapped in dependency('int')
2413   if (msgfmt.found() and
2414       cc.check_header('libintl.h', required: nlsopt,
2415         args: test_c_args, include_directories: postgres_inc))
2417     # in libc
2418     if cc.has_function('ngettext')
2419       libintl = declare_dependency()
2420     else
2421       libintl = cc.find_library('intl',
2422         has_headers: ['libintl.h'], required: nlsopt,
2423         header_include_directories: postgres_inc,
2424         dirs: test_lib_d)
2425     endif
2426   endif
2428   if libintl.found()
2429     i18n = import('i18n')
2430     cdata.set('ENABLE_NLS', 1)
2431   endif
2432 endif
2436 ###############################################################
2437 # Build
2438 ###############################################################
2440 # Set up compiler / linker arguments to be used everywhere, individual targets
2441 # can add further args directly, or indirectly via dependencies
2442 add_project_arguments(cflags, language: ['c'])
2443 add_project_arguments(cppflags, language: ['c'])
2444 add_project_arguments(cflags_warn, language: ['c'])
2445 add_project_arguments(cxxflags, language: ['cpp'])
2446 add_project_arguments(cppflags, language: ['cpp'])
2447 add_project_arguments(cxxflags_warn, language: ['cpp'])
2448 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2451 # Collect a number of lists of things while recursing through the source
2452 # tree. Later steps then can use those.
2454 # list of targets for various alias targets
2455 backend_targets = []
2456 bin_targets = []
2457 pl_targets = []
2458 contrib_targets = []
2459 testprep_targets = []
2462 # Define the tests to distribute them to the correct test styles later
2463 test_deps = []
2464 tests = []
2467 # Default options for targets
2469 # First identify rpaths
2470 bin_install_rpaths = []
2471 lib_install_rpaths = []
2472 mod_install_rpaths = []
2474 # Add extra_lib_dirs to rpath. Not needed on darwin, as the install_name of
2475 # libraries in extra_lib_dirs will be used anyway.
2476 if host_system != 'darwin'
2477   bin_install_rpaths += postgres_lib_d
2478   lib_install_rpaths += postgres_lib_d
2479   mod_install_rpaths += postgres_lib_d
2480 endif
2483 # Define arguments for default targets
2485 default_target_args = {
2486   'implicit_include_directories': false,
2487   'install': true,
2490 default_lib_args = default_target_args + {
2491   'name_prefix': '',
2492   'install_rpath': ':'.join(lib_install_rpaths),
2495 internal_lib_args = default_lib_args + {
2496   'build_by_default': false,
2497   'install': false,
2500 default_mod_args = default_lib_args + {
2501   'name_prefix': '',
2502   'install_dir': dir_lib_pkg,
2503   'install_rpath': ':'.join(mod_install_rpaths),
2506 default_bin_args = default_target_args + {
2507   'install_dir': dir_bin,
2508   'install_rpath': ':'.join(bin_install_rpaths),
2513 # Helper for exporting a limited number of symbols
2514 gen_export_kwargs = {
2515   'input': 'exports.txt',
2516   'output': '@BASENAME@.'+export_file_suffix,
2517   'command': [perl, files('src/tools/gen_export.pl'),
2518    '--format', export_file_format,
2519    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2520   'build_by_default': false,
2521   'install': false,
2526 # headers that the whole build tree depends on
2527 generated_headers = []
2528 # headers that the backend build depends on
2529 generated_backend_headers = []
2530 # configure_files() output, needs a way of converting to file names
2531 configure_files = []
2533 # generated files that might conflict with a partial in-tree autoconf build
2534 generated_sources = []
2535 # same, for paths that differ between autoconf / meson builds
2536 # elements are [dir, [files]]
2537 generated_sources_ac = {}
2540 # First visit src/include - all targets creating headers are defined
2541 # within. That makes it easy to add the necessary dependencies for the
2542 # subsequent build steps.
2544 subdir('src/include')
2546 subdir('config')
2548 # Then through src/port and src/common, as most other things depend on them
2550 frontend_port_code = declare_dependency(
2551   compile_args: ['-DFRONTEND'],
2552   include_directories: [postgres_inc],
2553   dependencies: os_deps,
2556 backend_port_code = declare_dependency(
2557   compile_args: ['-DBUILDING_DLL'],
2558   include_directories: [postgres_inc],
2559   sources: [errcodes], # errcodes.h is needed due to use of ereport
2560   dependencies: os_deps,
2563 subdir('src/port')
2565 frontend_common_code = declare_dependency(
2566   compile_args: ['-DFRONTEND'],
2567   include_directories: [postgres_inc],
2568   sources: generated_headers,
2569   dependencies: [os_deps, zlib, zstd],
2572 backend_common_code = declare_dependency(
2573   compile_args: ['-DBUILDING_DLL'],
2574   include_directories: [postgres_inc],
2575   sources: generated_headers,
2576   dependencies: [os_deps, zlib, zstd],
2579 subdir('src/common')
2581 frontend_shlib_code = declare_dependency(
2582   compile_args: ['-DFRONTEND'],
2583   include_directories: [postgres_inc],
2584   link_args: ldflags_sl,
2585   link_with: [pgport_shlib, common_shlib],
2586   sources: generated_headers,
2587   dependencies: [os_deps, libintl],
2590 libpq_deps += [
2591   frontend_shlib_code,
2592   thread_dep,
2594   gssapi,
2595   ldap_r,
2596   libintl,
2597   ssl,
2600 subdir('src/interfaces/libpq')
2601 # fe_utils depends on libpq
2602 subdir('src/fe_utils')
2604 frontend_code = declare_dependency(
2605   include_directories: [postgres_inc],
2606   link_with: [fe_utils, common_static, pgport_static],
2607   sources: generated_headers,
2608   dependencies: [os_deps, libintl],
2611 backend_both_deps += [
2612   thread_dep,
2613   bsd_auth,
2614   gssapi,
2615   icu,
2616   icu_i18n,
2617   ldap,
2618   libintl,
2619   libxml,
2620   lz4,
2621   pam,
2622   ssl,
2623   systemd,
2624   zlib,
2625   zstd,
2628 backend_mod_deps = backend_both_deps + os_deps
2630 backend_code = declare_dependency(
2631   compile_args: ['-DBUILDING_DLL'],
2632   include_directories: [postgres_inc],
2633   link_args: ldflags_be,
2634   link_with: [],
2635   sources: generated_headers + generated_backend_headers,
2636   dependencies: os_deps + backend_both_deps + backend_deps,
2639 # src/backend/meson.build defines backend_mod_code used for extension
2640 # libraries.
2643 # Then through the main sources. That way contrib can have dependencies on
2644 # main sources. Note that this explicitly doesn't enter src/test, right now a
2645 # few regression tests depend on contrib files.
2647 subdir('src')
2649 subdir('contrib')
2651 subdir('src/test')
2652 subdir('src/interfaces/libpq/test')
2653 subdir('src/interfaces/ecpg/test')
2655 subdir('doc/src/sgml')
2657 generated_sources_ac += {'': ['GNUmakefile']}
2660 # If there are any files in the source directory that we also generate in the
2661 # build directory, they might get preferred over the newly generated files,
2662 # e.g. because of a #include "file", which always will search in the current
2663 # directory first.
2664 message('checking for file conflicts between source and build directory')
2665 conflicting_files = []
2666 potentially_conflicting_files_t = []
2667 potentially_conflicting_files_t += generated_headers
2668 potentially_conflicting_files_t += generated_backend_headers
2669 potentially_conflicting_files_t += generated_backend_sources
2670 potentially_conflicting_files_t += generated_sources
2672 potentially_conflicting_files = []
2674 # convert all sources of potentially conflicting files into uniform shape
2675 foreach t : potentially_conflicting_files_t
2676   potentially_conflicting_files += t.full_path()
2677 endforeach
2678 foreach t : configure_files
2679   t = '@0@'.format(t)
2680   potentially_conflicting_files += meson.current_build_dir() / t
2681 endforeach
2682 foreach sub, fnames : generated_sources_ac
2683   sub = meson.build_root() / sub
2684   foreach fname : fnames
2685     potentially_conflicting_files += sub / fname
2686   endforeach
2687 endforeach
2689 # find and report conflicting files
2690 foreach build_path : potentially_conflicting_files
2691   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2692   # str.replace is in 0.56
2693   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2694   if fs.exists(src_path) or fs.is_symlink(src_path)
2695     conflicting_files += src_path
2696   endif
2697 endforeach
2698 # XXX: Perhaps we should generate a file that would clean these up? The list
2699 # can be long.
2700 if conflicting_files.length() > 0
2701   errmsg_cleanup = '''
2702 Conflicting files in source directory:
2703   @0@
2705 The conflicting files need to be removed, either by removing the files listed
2706 above, or by running configure and then make maintainer-clean.
2708   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2709   error(errmsg_nonclean_base.format(errmsg_cleanup))
2710 endif
2714 ###############################################################
2715 # Test prep
2716 ###############################################################
2718 # The determination of where a DESTDIR install points to is ugly, it's somewhat hard
2719 # to combine two absolute paths portably...
2721 prefix = get_option('prefix')
2723 test_prefix = prefix
2725 if fs.is_absolute(get_option('prefix'))
2726   if host_system == 'windows'
2727     if prefix.split(':\\').length() == 1
2728       # just a drive
2729       test_prefix = ''
2730     else
2731       test_prefix = prefix.split(':\\')[1]
2732     endif
2733   else
2734     assert(prefix.startswith('/'))
2735     test_prefix = './@0@'.format(prefix)
2736   endif
2737 endif
2739 # DESTDIR for the installation used to run tests in
2740 test_install_destdir = meson.build_root() / 'tmp_install/'
2741 # DESTDIR + prefix appropriately munged
2742 test_install_location = test_install_destdir / test_prefix
2745 meson_install_args = meson_args + ['install'] + {
2746     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
2747     'muon': []
2748 }[meson_impl]
2750 test('tmp_install',
2751     meson_bin, args: meson_install_args ,
2752     env: {'DESTDIR':test_install_destdir},
2753     priority: 100,
2754     timeout: 300,
2755     is_parallel: false,
2756     suite: ['setup'])
2758 test_result_dir = meson.build_root() / 'testrun'
2761 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
2762 # inevitable conflicts from running tests in parallel, hackishly assign
2763 # different ports for different tests.
2765 testport = 40000
2767 test_env = environment()
2769 temp_install_bindir = test_install_location / get_option('bindir')
2770 test_env.set('PG_REGRESS', pg_regress.full_path())
2771 test_env.set('REGRESS_SHLIB', regress_module.full_path())
2773 # Test suites that are not safe by default but can be run if selected
2774 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
2775 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
2776 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
2778 # Add the temporary installation to the library search path on platforms where
2779 # that works (everything but windows, basically). On windows everything
2780 # library-like gets installed into bindir, solving that issue.
2781 if library_path_var != ''
2782   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
2783 endif
2787 ###############################################################
2788 # Test Generation
2789 ###############################################################
2791 testwrap = files('src/tools/testwrap')
2793 foreach test_dir : tests
2794   testwrap_base = [
2795     testwrap,
2796     '--basedir', meson.build_root(),
2797     '--srcdir', test_dir['sd'],
2798     '--testgroup', test_dir['name'],
2799   ]
2801   foreach kind, v : test_dir
2802     if kind in ['sd', 'bd', 'name']
2803       continue
2804     endif
2806     t = test_dir[kind]
2808     if kind in ['regress', 'isolation', 'ecpg']
2809       if kind == 'regress'
2810         runner = pg_regress
2811       elif kind == 'isolation'
2812         runner = pg_isolation_regress
2813       elif kind == 'ecpg'
2814         runner = pg_regress_ecpg
2815       endif
2817       test_output = test_result_dir / test_dir['name'] / kind
2819       test_command = [
2820         runner.full_path(),
2821         '--inputdir', t.get('inputdir', test_dir['sd']),
2822         '--expecteddir', t.get('expecteddir', test_dir['sd']),
2823         '--outputdir', test_output,
2824         '--temp-instance', test_output / 'tmp_check',
2825         '--bindir', '',
2826         '--dlpath', test_dir['bd'],
2827         '--max-concurrent-tests=20',
2828         '--port', testport.to_string(),
2829       ] + t.get('regress_args', [])
2831       if t.has_key('schedule')
2832         test_command += ['--schedule', t['schedule'],]
2833       endif
2835       if kind == 'isolation'
2836         test_command += t.get('specs', [])
2837       else
2838         test_command += t.get('sql', [])
2839       endif
2841       env = test_env
2842       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
2844       test_kwargs = {
2845         'suite': [test_dir['name']],
2846         'priority': 10,
2847         'timeout': 1000,
2848         'depends': test_deps + t.get('deps', []),
2849         'env': env,
2850       } + t.get('test_kwargs', {})
2852       test(test_dir['name'] / kind,
2853         python,
2854         args: testwrap_base + [
2855           '--testname', kind,
2856           '--', test_command,
2857         ],
2858         kwargs: test_kwargs,
2859       )
2861       testport += 1
2862     elif kind == 'tap'
2863       if not tap_tests_enabled
2864         continue
2865       endif
2867       test_command = [
2868         perl.path(),
2869         '-I', meson.source_root() / 'src/test/perl',
2870         '-I', test_dir['sd'],
2871       ]
2873       # Add temporary install, the build directory for non-installed binaries and
2874       # also test/ for non-installed test binaries built separately.
2875       env = test_env
2876       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
2878       foreach name, value : t.get('env', {})
2879         env.set(name, value)
2880       endforeach
2882       test_kwargs = {
2883         'protocol': 'tap',
2884         'suite': [test_dir['name']],
2885         'timeout': 1000,
2886         'depends': test_deps + t.get('deps', []),
2887         'env': env,
2888       } + t.get('test_kwargs', {})
2890       foreach onetap : t['tests']
2891         # Make tap test names prettier, remove t/ and .pl
2892         onetap_p = onetap
2893         if onetap_p.startswith('t/')
2894           onetap_p = onetap.split('t/')[1]
2895         endif
2896         if onetap_p.endswith('.pl')
2897           onetap_p = fs.stem(onetap_p)
2898         endif
2900         test(test_dir['name'] / onetap_p,
2901           python,
2902           kwargs: test_kwargs,
2903           args: testwrap_base + [
2904             '--testname', onetap_p,
2905             '--', test_command,
2906             test_dir['sd'] / onetap,
2907           ],
2908         )
2909       endforeach
2910     else
2911       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
2912     endif
2914   endforeach # kinds of tests
2916 endforeach # directories with tests
2920 ###############################################################
2921 # Pseudo targets
2922 ###############################################################
2924 alias_target('backend', backend_targets)
2925 alias_target('bin', bin_targets + [libpq_st])
2926 alias_target('pl', pl_targets)
2927 alias_target('contrib', contrib_targets)
2928 alias_target('testprep', testprep_targets)
2932 ###############################################################
2933 # The End, The End, My Friend
2934 ###############################################################
2936 if meson.version().version_compare('>=0.57')
2938   summary(
2939     {
2940       'data block size': cdata.get('BLCKSZ'),
2941       'WAL block size': cdata.get('XLOG_BLCKSZ') / 1024,
2942       'segment size': cdata.get('RELSEG_SIZE') / 131072,
2943     },
2944     section: 'Data layout',
2945   )
2947   summary(
2948     {
2949       'host system': '@0@ @1@'.format(host_system, host_cpu),
2950       'build system': '@0@ @1@'.format(build_machine.system(),
2951                                        build_machine.cpu_family()),
2952     },
2953     section: 'System',
2954   )
2956   summary(
2957     {
2958       'linker': '@0@'.format(cc.get_linker_id()),
2959       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
2960     },
2961     section: 'Compiler',
2962   )
2964   summary(
2965     {
2966       'CPP FLAGS': ' '.join(cppflags),
2967       'C FLAGS, functional': ' '.join(cflags),
2968       'C FLAGS, warnings': ' '.join(cflags_warn),
2969     },
2970     section: 'Compiler Flags',
2971   )
2973   if llvm.found()
2974     summary(
2975       {
2976         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
2977       },
2978       section: 'Compiler',
2979     )
2981     summary(
2982       {
2983         'C++ FLAGS, functional': ' '.join(cxxflags),
2984         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
2985       },
2986       section: 'Compiler Flags',
2987     )
2988   endif
2990   summary(
2991     {
2992       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
2993       'dtrace': dtrace,
2994     },
2995     section: 'Programs',
2996   )
2998   summary(
2999     {
3000       'bonjour': bonjour,
3001       'bsd_auth': bsd_auth,
3002       'gss': gssapi,
3003       'icu': icu,
3004       'ldap': ldap,
3005       'libxml': libxml,
3006       'libxslt': libxslt,
3007       'llvm': llvm,
3008       'lz4': lz4,
3009       'nls': libintl,
3010       'pam': pam,
3011       'plperl': perl_dep,
3012       'plpython': python3_dep,
3013       'pltcl': tcl_dep,
3014       'readline': readline,
3015       'selinux': selinux,
3016       'ssl': ssl,
3017       'systemd': systemd,
3018       'uuid': uuid,
3019       'zlib': zlib,
3020       'zstd': zstd,
3021     },
3022     section: 'External libraries',
3023   )
3025 endif