Refine query jumbling handling for CallStmt
[pgsql.git] / meson.build
blobf1ce4cb8e03ce591340bb46070fb69dc76bf3806
1 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
3 # Entry point for building PostgreSQL with meson
5 # Good starting points for writing meson.build files are:
6 #  - https://mesonbuild.com/Syntax.html
7 #  - https://mesonbuild.com/Reference-manual.html
9 project('postgresql',
10   ['c'],
11   version: '16devel',
12   license: 'PostgreSQL',
14   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
15   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
16   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
17   meson_version: '>=0.54',
18   default_options: [
19     'warning_level=1', #-Wall equivalent
20     'b_pch=false',
21     'buildtype=release',
22     # For compatibility with the autoconf build, set a default prefix. This
23     # works even on windows, where it's a drive-relative path (i.e. when on
24     # d:/somepath it'll install to d:/usr/local/pgsql)
25     'prefix=/usr/local/pgsql',
26   ]
31 ###############################################################
32 # Basic prep
33 ###############################################################
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
42 cc = meson.get_compiler('c')
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
49 ###############################################################
50 # Safety first
51 ###############################################################
53 # It's very easy to get into confusing states when the source directory
54 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
55 # refuse to build in that case.
57 # There's a more elaborate check later, that checks for conflicts around all
58 # generated files. But we can only do that much further down the line, so this
59 # quick check seems worth it. Adhering to this advice should clean up the
60 # conflict, but won't protect against somebody doing make distclean or just
61 # removing pg_config.h
62 errmsg_nonclean_base = '''
63 ****
64 Non-clean source code directory detected.
66 To build with meson the source tree may not have an in-place, ./configure
67 style, build configured. You can have both meson and ./configure style builds
68 for the same source tree by building out-of-source / VPATH with
69 configure. Alternatively use a separate check out for meson based builds.
71 @0@
72 ****'''
73 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
74   errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
75   error(errmsg_nonclean_base.format(errmsg_cleanup))
76 endif
80 ###############################################################
81 # Variables to be determined
82 ###############################################################
84 postgres_inc_d = ['src/include']
85 postgres_inc_d += get_option('extra_include_dirs')
87 postgres_lib_d = get_option('extra_lib_dirs')
89 cppflags = []
91 cflags = []
92 cxxflags = []
93 cflags_warn = []
94 cxxflags_warn = []
95 cflags_mod = []
96 cxxflags_mod = []
98 ldflags = []
99 ldflags_be = []
100 ldflags_sl = []
101 ldflags_mod = []
103 test_c_args = []
105 os_deps = []
106 backend_both_deps = []
107 backend_deps = []
108 libpq_deps = []
110 pg_sysroot = ''
112 # source of data for pg_config.h etc
113 cdata = configuration_data()
117 ###############################################################
118 # Version and other metadata
119 ###############################################################
121 pg_version = meson.project_version()
123 if pg_version.endswith('devel')
124   pg_version_arr = [pg_version.split('devel')[0], '0']
125 elif pg_version.contains('beta')
126   pg_version_arr = [pg_version.split('beta')[0], '0']
127 elif pg_version.contains('rc')
128   pg_version_arr = [pg_version.split('rc')[0], '0']
129 else
130   pg_version_arr = pg_version.split('.')
131 endif
133 pg_version_major = pg_version_arr[0].to_int()
134 pg_version_minor = pg_version_arr[1].to_int()
135 pg_version_num = (pg_version_major * 10000) + pg_version_minor
137 pg_url = 'https://www.postgresql.org/'
139 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
140 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
141 cdata.set_quoted('PACKAGE_URL', pg_url)
142 cdata.set_quoted('PACKAGE_VERSION', pg_version)
143 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
144 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
146 pg_version += get_option('extra_version')
147 cdata.set_quoted('PG_VERSION', pg_version)
148 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
149 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
150 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
151 cdata.set('PG_VERSION_NUM', pg_version_num)
152 # PG_VERSION_STR is built later, it depends compiler test results
153 cdata.set_quoted('CONFIGURE_ARGS', '')
157 ###############################################################
158 # Basic platform specific configuration
159 ###############################################################
161 # meson's system names don't quite map to our "traditional" names. In some
162 # places we need the "traditional" name, e.g., for mapping
163 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
164 # that purpose.
165 portname = host_system
167 exesuffix = '' # overridden below where necessary
168 dlsuffix = '.so' # overridden below where necessary
169 library_path_var = 'LD_LIBRARY_PATH'
171 # Format of file to control exports from libraries, and how to pass them to
172 # the compiler. For export_fmt @0@ is the path to the file export file.
173 export_file_format = 'gnu'
174 export_file_suffix = 'list'
175 export_fmt = '-Wl,--version-script=@0@'
177 # Flags to add when linking a postgres extension, @0@ is path to
178 # the relevant object on the platform.
179 mod_link_args_fmt = []
181 memset_loop_limit = 1024
183 # Choice of shared memory and semaphore implementation
184 shmem_kind = 'sysv'
185 sema_kind = 'sysv'
187 # We implement support for some operating systems by pretending they're
188 # another. Map here, before determining system properties below
189 if host_system == 'dragonfly'
190   # apparently the most similar
191   host_system = 'netbsd'
192 endif
194 if host_system == 'aix'
195   library_path_var = 'LIBPATH'
197   export_file_format = 'aix'
198   export_fmt = '-Wl,-bE:@0@'
199   mod_link_args_fmt = ['-Wl,-bI:@0@']
200   mod_link_with_dir = 'libdir'
201   mod_link_with_name = '@0@.imp'
203   # M:SRE sets a flag indicating that an object is a shared library. Seems to
204   # work in some circumstances without, but required in others.
205   ldflags_sl += '-Wl,-bM:SRE'
206   ldflags_be += '-Wl,-brtllib'
208   # Native memset() is faster, tested on:
209   # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
210   # - AIX 5.3 ML3, gcc 4.0.1
211   memset_loop_limit = 0
213 elif host_system == 'cygwin'
214   sema_kind = 'unnamed_posix'
215   cppflags += '-D_GNU_SOURCE'
216   dlsuffix = '.dll'
217   mod_link_args_fmt = ['@0@']
218   mod_link_with_name = 'lib@0@.exe.a'
219   mod_link_with_dir = 'libdir'
221 elif host_system == 'darwin'
222   dlsuffix = '.dylib'
223   library_path_var = 'DYLD_LIBRARY_PATH'
225   export_file_format = 'darwin'
226   export_fmt = '-exported_symbols_list=@0@'
228   mod_link_args_fmt = ['-bundle_loader', '@0@']
229   mod_link_with_dir = 'bindir'
230   mod_link_with_name = '@0@'
232   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
233   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
234   message('darwin sysroot: @0@'.format(pg_sysroot))
235   cflags += ['-isysroot', pg_sysroot]
236   ldflags += ['-isysroot', pg_sysroot]
237   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
238   # don't want because a) it's different from what we do for autoconf, b) it
239   # causes warnings starting in macOS Ventura
240   ldflags_mod += ['-Wl,-undefined,error']
242 elif host_system == 'freebsd'
243   sema_kind = 'unnamed_posix'
245 elif host_system == 'linux'
246   sema_kind = 'unnamed_posix'
247   cppflags += '-D_GNU_SOURCE'
249 elif host_system == 'netbsd'
250   # We must resolve all dynamic linking in the core server at program start.
251   # Otherwise the postmaster can self-deadlock due to signals interrupting
252   # resolution of calls, since NetBSD's linker takes a lock while doing that
253   # and some postmaster signal handlers do things that will also acquire that
254   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
255   # While there's not a hard reason to adopt these settings for our other
256   # executables, there's also little reason not to, so just add them to
257   # LDFLAGS.
258   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
260 elif host_system == 'openbsd'
261   # you're ok
263 elif host_system == 'sunos'
264   portname = 'solaris'
265   export_fmt = '-Wl,-M@0@'
266   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
268 elif host_system == 'windows'
269   portname = 'win32'
270   exesuffix = '.exe'
271   dlsuffix = '.dll'
272   library_path_var = ''
274   export_file_format = 'win'
275   export_file_suffix = 'def'
276   if cc.get_id() == 'msvc'
277     export_fmt = '/DEF:@0@'
278     mod_link_with_name = '@0@.exe.lib'
279   else
280     export_fmt = '@0@'
281     mod_link_with_name = 'lib@0@.exe.a'
282   endif
283   mod_link_args_fmt = ['@0@']
284   mod_link_with_dir = 'libdir'
286   shmem_kind = 'win32'
287   sema_kind = 'win32'
289   cdata.set('WIN32_STACK_RLIMIT', 4194304)
290   if cc.get_id() == 'msvc'
291     ldflags += '/INCREMENTAL:NO'
292     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
293     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
294   else
295     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
296     # Need to allow multiple definitions, we e.g. want to override getopt.
297     ldflags += '-Wl,--allow-multiple-definition'
298     # Ensure we get MSVC-like linking behavior.
299     ldflags += '-Wl,--disable-auto-import'
300   endif
302   os_deps += cc.find_library('ws2_32', required: true)
303   secur32_dep = cc.find_library('secur32', required: true)
304   backend_deps += secur32_dep
305   libpq_deps += secur32_dep
307   postgres_inc_d += 'src/include/port/win32'
308   if cc.get_id() == 'msvc'
309     postgres_inc_d += 'src/include/port/win32_msvc'
310   endif
312   windows = import('windows')
314 else
315   # XXX: Should we add an option to override the host_system as an escape
316   # hatch?
317   error('unknown host system: @0@'.format(host_system))
318 endif
322 ###############################################################
323 # Program paths
324 ###############################################################
326 # External programs
327 perl = find_program(get_option('PERL'), required: true, native: true)
328 python = find_program(get_option('PYTHON'), required: true, native: true)
329 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
330 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
331 sed = find_program(get_option('SED'), 'sed', native: true)
332 prove = find_program(get_option('PROVE'), native: true, required: false)
333 tar = find_program(get_option('TAR'), native: true)
334 gzip = find_program(get_option('GZIP'), native: true)
335 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
336 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
337 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
338 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
339 missing = find_program('config/missing', native: true)
340 cp = find_program('cp', required: false, native: true)
342 bison_flags = []
343 if bison.found()
344   bison_version_c = run_command(bison, '--version', check: true)
345   # bison version string helpfully is something like
346   # >>bison (GNU bison) 3.8.1<<
347   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
348   if bison_version.version_compare('>=3.0')
349     bison_flags += ['-Wno-deprecated']
350   endif
351 endif
352 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
353 bison_kw = {
354   'output': ['@BASENAME@.c', '@BASENAME@.h'],
355   'command': bison_cmd,
358 flex_flags = []
359 flex_wrapper = files('src/tools/pgflex')
360 flex_cmd = [python, flex_wrapper,
361   '--builddir', '@BUILD_ROOT@',
362   '--srcdir', '@SOURCE_ROOT@',
363   '--privatedir', '@PRIVATE_DIR@',
364   '--flex', flex, '--perl', perl,
365   '-i', '@INPUT@', '-o', '@OUTPUT0@',
368 wget = find_program('wget', required: false, native: true)
369 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
373 ###############################################################
374 # Path to meson (for tests etc)
375 ###############################################################
377 # NB: this should really be part of meson, see
378 # https://github.com/mesonbuild/meson/issues/8511
379 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
381 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
382   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
383     meson_binpath_r.returncode(),
384     meson_binpath_r.stdout(),
385     meson_binpath_r.stderr()))
386 endif
388 meson_binpath_s = meson_binpath_r.stdout().split('\n')
389 meson_binpath_len = meson_binpath_s.length()
391 if meson_binpath_len < 1
392   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
393 endif
395 i = 0
396 meson_impl = ''
397 meson_binpath = ''
398 meson_args = []
399 foreach e : meson_binpath_s
400   if i == 0
401     meson_impl = e
402   elif i == 1
403     meson_binpath = e
404   else
405     meson_args += e
406   endif
407   i += 1
408 endforeach
410 if meson_impl not in ['muon', 'meson']
411   error('unknown meson implementation "@0@"'.format(meson_impl))
412 endif
414 meson_bin = find_program(meson_binpath, native: true)
418 ###############################################################
419 # Option Handling
420 ###############################################################
422 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
424 blocksize = get_option('blocksize').to_int() * 1024
426 if get_option('segsize_blocks') != 0
427   if get_option('segsize') != 1
428     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
429   endif
431   segsize = get_option('segsize_blocks')
432 else
433   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
434 endif
436 cdata.set('BLCKSZ', blocksize, description:
437 '''Size of a disk block --- this also limits the size of a tuple. You can set
438    it bigger if you need bigger tuples (although TOAST should reduce the need
439    to have large tuples, since fields can be spread across multiple tuples).
440    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
441    currently 2^15 (32768). This is determined by the 15-bit widths of the
442    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
443    Changing BLCKSZ requires an initdb.''')
445 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
446 cdata.set('RELSEG_SIZE', segsize)
447 cdata.set('DEF_PGPORT', get_option('pgport'))
448 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
449 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
450 if get_option('system_tzdata') != ''
451   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
452 endif
456 ###############################################################
457 # Directories
458 ###############################################################
460 # These are set by the equivalent --xxxdir configure options.  We
461 # append "postgresql" to some of them, if the string does not already
462 # contain "pgsql" or "postgres", in order to avoid directory clutter.
464 pkg = 'postgresql'
466 dir_prefix = get_option('prefix')
468 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
470 dir_bin = get_option('bindir')
472 dir_data = get_option('datadir')
473 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
474   dir_data = dir_data / pkg
475 endif
477 dir_sysconf = get_option('sysconfdir')
478 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
479   dir_sysconf = dir_sysconf / pkg
480 endif
482 dir_lib = get_option('libdir')
484 dir_lib_pkg = dir_lib
485 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
486   dir_lib_pkg = dir_lib_pkg / pkg
487 endif
489 dir_pgxs = dir_lib_pkg / 'pgxs'
491 dir_include = get_option('includedir')
493 dir_include_pkg = dir_include
494 dir_include_pkg_rel = ''
495 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
496   dir_include_pkg = dir_include_pkg / pkg
497   dir_include_pkg_rel = pkg
498 endif
500 dir_man = get_option('mandir')
502 # FIXME: These used to be separately configurable - worth adding?
503 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
504 dir_doc_html = dir_doc
506 dir_locale = get_option('localedir')
509 # Derived values
510 dir_bitcode = dir_lib_pkg / 'bitcode'
511 dir_include_internal = dir_include_pkg / 'internal'
512 dir_include_server = dir_include_pkg / 'server'
513 dir_include_extension = dir_include_server / 'extension'
514 dir_data_extension = dir_data / 'extension'
518 ###############################################################
519 # Search paths, preparation for compiler tests
521 # NB: Arguments added later are not automatically used for subsequent
522 # configuration-time checks (so they are more isolated). If they should be
523 # used, they need to be added to test_c_args as well.
524 ###############################################################
526 postgres_inc = [include_directories(postgres_inc_d)]
527 test_lib_d = postgres_lib_d
528 test_c_args = cppflags + cflags
532 ###############################################################
533 # Library: bsd-auth
534 ###############################################################
536 bsd_authopt = get_option('bsd_auth')
537 bsd_auth = not_found_dep
538 if cc.check_header('bsd_auth.h', required: bsd_authopt,
539     args: test_c_args, include_directories: postgres_inc)
540   cdata.set('USE_BSD_AUTH', 1)
541   bsd_auth = declare_dependency()
542 endif
546 ###############################################################
547 # Library: bonjour
549 # For now don't search for DNSServiceRegister in a library - only Apple's
550 # Bonjour implementation, which is always linked, works.
551 ###############################################################
553 bonjouropt = get_option('bonjour')
554 bonjour = dependency('', required : false)
555 if cc.check_header('dns_sd.h', required: bonjouropt,
556     args: test_c_args, include_directories: postgres_inc) and \
557    cc.has_function('DNSServiceRegister',
558     args: test_c_args, include_directories: postgres_inc)
559   cdata.set('USE_BONJOUR', 1)
560   bonjour = declare_dependency()
561 endif
565 ###############################################################
566 # Library: GSSAPI
567 ###############################################################
569 gssapiopt = get_option('gssapi')
570 krb_srvtab = ''
571 have_gssapi = false
572 if not gssapiopt.disabled()
573   gssapi = dependency('krb5-gssapi', required: gssapiopt)
574   have_gssapi = gssapi.found()
576   if not have_gssapi
577   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
578       args: test_c_args, include_directories: postgres_inc)
579     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
580   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
581     cdata.set('HAVE_GSSAPI_H', 1)
582   else
583     have_gssapi = false
584   endif
586   if not have_gssapi
587   elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
588       args: test_c_args, include_directories: postgres_inc)
589     cdata.set('ENABLE_GSS', 1)
591     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
592     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
593   elif gssapiopt.enabled()
594     error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
595   else
596     have_gssapi = false
597   endif
598 endif
599 if not have_gssapi
600   gssapi = not_found_dep
601 endif
605 ###############################################################
606 # Library: ldap
607 ###############################################################
609 ldapopt = get_option('ldap')
610 if ldapopt.disabled()
611   ldap = not_found_dep
612   ldap_r = not_found_dep
613 elif host_system == 'windows'
614   ldap = cc.find_library('wldap32', required: ldapopt)
615   ldap_r = ldap
616 else
617   # macos framework dependency is buggy for ldap (one can argue whether it's
618   # Apple's or meson's fault), leading to an endless recursion with ldap.h
619   # including itself. See https://github.com/mesonbuild/meson/issues/10002
620   # Luckily we only need pkg-config support, so the workaround isn't
621   # complicated.
622   ldap = dependency('ldap', method: 'pkg-config', required: false)
623   ldap_r = ldap
625   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
626   # installed
627   if not ldap.found()
628     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
629       has_headers: 'ldap.h', header_include_directories: postgres_inc)
631     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
632     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
633     # library from a separate OpenLDAP installation).  The most reliable
634     # way to check that is to check for a function introduced in 2.5.
635     if not ldap.found()
636       # don't have ldap, we shouldn't check for ldap_r
637     elif cc.has_function('ldap_verify_credentials',
638         dependencies: ldap, args: test_c_args)
639       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
640     else
642       # Use ldap_r for FE if available, else assume ldap is thread-safe.
643       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
644         has_headers: 'ldap.h', header_include_directories: postgres_inc)
645       if not ldap_r.found()
646         ldap_r = ldap
647       else
648         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
649         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
650       endif
652       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
653       # process.  Check for OpenLDAP versions known not to tolerate doing so;
654       # assume non-OpenLDAP implementations are safe.  The dblink test suite
655       # exercises the hazardous interaction directly.
656       compat_test_code = '''
657 #include <ldap.h>
658 #if !defined(LDAP_VENDOR_VERSION) || \
659      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
660       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
661 choke me
662 #endif
664       if not cc.compiles(compat_test_code,
665           name: 'LDAP implementation compatible',
666           dependencies: ldap, args: test_c_args)
667         warning('''
668 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
669 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
670 *** also uses LDAP will crash on exit.''')
671       endif
672     endif
673   endif
675   # XXX: this shouldn't be tested in the windows case, but should be tested in
676   # the dependency() success case
677   if ldap.found() and cc.has_function('ldap_initialize',
678       dependencies: ldap, args: test_c_args)
679     cdata.set('HAVE_LDAP_INITIALIZE', 1)
680   endif
681 endif
683 if ldap.found()
684   assert(ldap_r.found())
685   cdata.set('USE_LDAP', 1)
686 else
687   assert(not ldap_r.found())
688 endif
692 ###############################################################
693 # Library: LLVM
694 ###############################################################
696 llvmopt = get_option('llvm')
697 if not llvmopt.disabled()
698   add_languages('cpp', required: true, native: false)
699   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
701   if llvm.found()
703     cdata.set('USE_LLVM', 1)
705     cpp = meson.get_compiler('cpp')
707     llvm_binpath = llvm.get_variable(configtool: 'bindir')
709     ccache = find_program('ccache', native: true, required: false)
710     clang = find_program(llvm_binpath / 'clang', required: true)
711   endif
712 else
713   llvm = not_found_dep
714 endif
718 ###############################################################
719 # Library: icu
720 ###############################################################
722 icuopt = get_option('icu')
723 if not icuopt.disabled()
724   icu = dependency('icu-uc', required: icuopt.enabled())
725   icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
727   if icu.found()
728     cdata.set('USE_ICU', 1)
729   endif
731 else
732   icu = not_found_dep
733   icu_i18n = not_found_dep
734 endif
738 ###############################################################
739 # Library: libxml
740 ###############################################################
742 libxmlopt = get_option('libxml')
743 if not libxmlopt.disabled()
744   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
746   if libxml.found()
747     cdata.set('USE_LIBXML', 1)
748   endif
749 else
750   libxml = not_found_dep
751 endif
755 ###############################################################
756 # Library: libxslt
757 ###############################################################
759 libxsltopt = get_option('libxslt')
760 if not libxsltopt.disabled()
761   libxslt = dependency('libxslt', required: libxsltopt)
763   if libxslt.found()
764     cdata.set('USE_LIBXSLT', 1)
765   endif
766 else
767   libxslt = not_found_dep
768 endif
772 ###############################################################
773 # Library: lz4
774 ###############################################################
776 lz4opt = get_option('lz4')
777 if not lz4opt.disabled()
778   lz4 = dependency('liblz4', required: lz4opt)
780   if lz4.found()
781     cdata.set('USE_LZ4', 1)
782     cdata.set('HAVE_LIBLZ4', 1)
783   endif
785 else
786   lz4 = not_found_dep
787 endif
791 ###############################################################
792 # Library: Tcl (for pltcl)
794 # NB: tclConfig.sh is used in autoconf build for getting
795 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
796 # variables. For now we have not seen a need to copy
797 # that behaviour to the meson build.
798 ###############################################################
800 tclopt = get_option('pltcl')
801 tcl_version = get_option('tcl_version')
802 tcl_dep = not_found_dep
803 if not tclopt.disabled()
805   # via pkg-config
806   tcl_dep = dependency(tcl_version, required: false)
808   if not tcl_dep.found()
809     tcl_dep = cc.find_library(tcl_version,
810       required: tclopt,
811       dirs: test_lib_d)
812   endif
814   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
815     tcl_dep = not_found_dep
816   endif
817 endif
821 ###############################################################
822 # Library: pam
823 ###############################################################
825 pamopt = get_option('pam')
826 if not pamopt.disabled()
827   pam = dependency('pam', required: false)
829   if not pam.found()
830     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
831   endif
833   if pam.found()
834     pam_header_found = false
836     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
837     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
838         args: test_c_args, include_directories: postgres_inc)
839       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
840       pam_header_found = true
841     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
842         args: test_c_args, include_directories: postgres_inc)
843       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
844       pam_header_found = true
845     endif
847     if pam_header_found
848       cdata.set('USE_PAM', 1)
849     else
850       pam = not_found_dep
851     endif
852   endif
853 else
854   pam = not_found_dep
855 endif
859 ###############################################################
860 # Library: Perl (for plperl)
861 ###############################################################
863 perlopt = get_option('plperl')
864 perl_dep = not_found_dep
865 if not perlopt.disabled()
866   perl_may_work = true
868   # First verify that perl has the necessary dependencies installed
869   perl_mods = run_command(
870     [perl,
871      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
872      '-e', ''],
873     check: false)
874   if perl_mods.returncode() != 0
875     perl_may_work = false
876     perl_msg = 'perl installation does not have the required modules'
877   endif
879   # Then inquire perl about its configuration
880   if perl_may_work
881     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
882     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
883     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
884     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
885     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
887     perl_inc_dir = '@0@/CORE'.format(archlibexp)
889     if perlversion.version_compare('< 5.14')
890       perl_may_work = false
891       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
892     elif useshrplib != 'true'
893       perl_may_work = false
894       perl_msg = 'need a shared perl'
895     endif
896   endif
898   if perl_may_work
899     # On most platforms, archlibexp is also where the Perl include files live ...
900     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
901     # ... but on newer macOS versions, we must use -iwithsysroot to look
902     # under sysroot
903     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
904        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
905       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
906     endif
908     # check compiler finds header
909     if not cc.has_header('perl.h', required: false,
910         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
911       perl_may_work = false
912       perl_msg = 'missing perl.h'
913     endif
914   endif
916   if perl_may_work
917     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
919     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
920     foreach flag : perl_ccflags_r.split(' ')
921       if flag.startswith('-D') and \
922           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
923         perl_ccflags += flag
924       endif
925     endforeach
927     if host_system == 'windows'
928       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
930       if cc.get_id() == 'msvc'
931         # prevent binary mismatch between MSVC built plperl and Strawberry or
932         # msys ucrt perl libraries
933         perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
934       endif
935     endif
937     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
938     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
940     # We are after Embed's ldopts, but without the subset mentioned in
941     # Config's ccdlflags and ldflags.  (Those are the choices of those who
942     # built the Perl installation, which are not necessarily appropriate
943     # for building PostgreSQL.)
944     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
945     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
946     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
948     perl_ldopts = []
949     foreach ldopt : ldopts.split(' ')
950       if ldopt == '' or ldopt in undesired
951         continue
952       endif
954       perl_ldopts += ldopt.strip('"')
955     endforeach
957     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
958     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
960     perl_dep_int = declare_dependency(
961       compile_args: perl_ccflags,
962       link_args: perl_ldopts,
963       version: perlversion,
964     )
966     # While we're at it, check that we can link to libperl.
967     # On most platforms, if perl.h is there then libperl.so will be too, but
968     # at this writing Debian packages them separately.
969     perl_link_test = '''
970 /* see plperl.h */
971 #ifdef _MSC_VER
972 #define __inline__ inline
973 #endif
974 #include <EXTERN.h>
975 #include <perl.h>
976 int main(void)
978 perl_alloc();
979 }'''
980     if not cc.links(perl_link_test, name: 'libperl',
981           args: test_c_args + perl_ccflags + perl_ldopts,
982           include_directories: postgres_inc)
983       perl_may_work = false
984       perl_msg = 'missing libperl'
985     endif
987   endif # perl_may_work
989   if perl_may_work
990     perl_dep = perl_dep_int
991   else
992     if perlopt.enabled()
993       error('dependency plperl failed: @0@'.format(perl_msg))
994     else
995       message('disabling optional dependency plperl: @0@'.format(perl_msg))
996     endif
997   endif
998 endif
1002 ###############################################################
1003 # Library: Python (for plpython)
1004 ###############################################################
1006 pyopt = get_option('plpython')
1007 if not pyopt.disabled()
1008   pm = import('python')
1009   python3_inst = pm.find_installation(required: pyopt.enabled())
1010   python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
1011   if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
1012     python3_dep = not_found_dep
1013   endif
1014 else
1015   python3_dep = not_found_dep
1016 endif
1020 ###############################################################
1021 # Library: Readline
1022 ###############################################################
1024 if not get_option('readline').disabled()
1025   libedit_preferred = get_option('libedit_preferred')
1026   # Set the order of readline dependencies
1027   check_readline_deps = libedit_preferred ? \
1028     ['libedit', 'readline'] : ['readline', 'libedit']
1030   foreach readline_dep : check_readline_deps
1031     readline = dependency(readline_dep, required: false)
1032     if not readline.found()
1033       readline = cc.find_library(readline_dep,
1034         required: get_option('readline').enabled(),
1035         dirs: test_lib_d)
1036     endif
1037     if readline.found()
1038       break
1039     endif
1040   endforeach
1042   if readline.found()
1043     cdata.set('HAVE_LIBREADLINE', 1)
1045     editline_prefix = {
1046       'header_prefix': 'editline/',
1047       'flag_prefix': 'EDITLINE_',
1048     }
1049     readline_prefix = {
1050       'header_prefix': 'readline/',
1051       'flag_prefix': 'READLINE_',
1052     }
1053     default_prefix = {
1054       'header_prefix': '',
1055       'flag_prefix': '',
1056     }
1058     # Set the order of prefixes
1059     prefixes = libedit_preferred ? \
1060       [editline_prefix, default_prefix, readline_prefix] : \
1061       [readline_prefix, default_prefix, editline_prefix]
1063     at_least_one_header_found = false
1064     foreach header : ['history', 'readline']
1065       is_found = false
1066       foreach prefix : prefixes
1067         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1068         # Check history.h and readline.h
1069         if not is_found and cc.has_header(header_file,
1070             args: test_c_args, include_directories: postgres_inc,
1071             dependencies: [readline], required: false)
1072           if header == 'readline'
1073             readline_h = header_file
1074           endif
1075           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1076           is_found = true
1077           at_least_one_header_found = true
1078         endif
1079       endforeach
1080     endforeach
1082     if not at_least_one_header_found
1083       error('''readline header not found
1084 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1085 failure. It is possible the compiler isn't looking in the proper directory.
1086 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1087     endif
1089     check_funcs = [
1090       'append_history',
1091       'history_truncate_file',
1092       'rl_completion_matches',
1093       'rl_filename_completion_function',
1094       'rl_reset_screen_size',
1095       'rl_variable_bind',
1096     ]
1098     foreach func : check_funcs
1099       found = cc.has_function(func, dependencies: [readline],
1100         args: test_c_args, include_directories: postgres_inc)
1101       cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1102     endforeach
1104     check_vars = [
1105       'rl_completion_suppress_quote',
1106       'rl_filename_quote_characters',
1107       'rl_filename_quoting_function',
1108     ]
1110     foreach var : check_vars
1111       cdata.set('HAVE_'+var.to_upper(),
1112         cc.has_header_symbol(readline_h, var,
1113           args: test_c_args, include_directories: postgres_inc,
1114           prefix: '#include <stdio.h>',
1115           dependencies: [readline]) ? 1 : false)
1116     endforeach
1118     # If found via cc.find_library() ensure headers are found when using the
1119     # dependency. On meson < 0.57 one cannot do compiler checks using the
1120     # dependency returned by declare_dependency(), so we can't do this above.
1121     if readline.type_name() == 'library'
1122       readline = declare_dependency(dependencies: readline,
1123         include_directories: postgres_inc)
1124     endif
1126     # On windows with mingw readline requires auto-import to successfully
1127     # link, as the headers don't use declspec(dllimport)
1128     if host_system == 'windows' and cc.get_id() != 'msvc'
1129       readline = declare_dependency(dependencies: readline,
1130         link_args: '-Wl,--enable-auto-import')
1131     endif
1132   endif
1134   # XXX: Figure out whether to implement mingw warning equivalent
1135 else
1136   readline = not_found_dep
1137 endif
1141 ###############################################################
1142 # Library: selinux
1143 ###############################################################
1145 selinux = not_found_dep
1146 selinuxopt = get_option('selinux')
1147 if meson.version().version_compare('>=0.59')
1148   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1149 endif
1150 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1151 cdata.set('HAVE_LIBSELINUX',
1152   selinux.found() ? 1 : false)
1156 ###############################################################
1157 # Library: systemd
1158 ###############################################################
1160 systemd = not_found_dep
1161 systemdopt = get_option('systemd')
1162 if meson.version().version_compare('>=0.59')
1163   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1164 endif
1165 systemd = dependency('libsystemd', required: systemdopt)
1166 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1170 ###############################################################
1171 # Library: SSL
1172 ###############################################################
1174 if get_option('ssl') == 'openssl'
1176   # Try to find openssl via pkg-config et al, if that doesn't work
1177   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1178   # the library names that we know about.
1180   # via pkg-config et al
1181   ssl = dependency('openssl', required: false)
1183   # via library + headers
1184   if not ssl.found()
1185     ssl_lib = cc.find_library('ssl',
1186       dirs: test_lib_d,
1187       header_include_directories: postgres_inc,
1188       has_headers: ['openssl/ssl.h', 'openssl/err.h'])
1189     crypto_lib = cc.find_library('crypto',
1190       dirs: test_lib_d,
1191       header_include_directories: postgres_inc)
1192     ssl_int = [ssl_lib, crypto_lib]
1194     ssl = declare_dependency(dependencies: ssl_int,
1195                              include_directories: postgres_inc)
1196   else
1197     cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
1198     cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
1200     ssl_int = [ssl]
1201   endif
1203   check_funcs = [
1204     ['CRYPTO_new_ex_data', {'required': true}],
1205     ['SSL_new', {'required': true}],
1207     # Function introduced in OpenSSL 1.0.2.
1208     ['X509_get_signature_nid'],
1210     # Functions introduced in OpenSSL 1.1.0. We used to check for
1211     # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1212     # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1213     # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1214     # functions.
1215     ['OPENSSL_init_ssl'],
1216     ['BIO_get_data'],
1217     ['BIO_meth_new'],
1218     ['ASN1_STRING_get0_data'],
1219     ['HMAC_CTX_new'],
1220     ['HMAC_CTX_free'],
1222     # OpenSSL versions before 1.1.0 required setting callback functions, for
1223     # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1224     # function was removed.
1225     ['CRYPTO_lock'],
1227     # Function introduced in OpenSSL 1.1.1
1228     ['X509_get_signature_info'],
1229   ]
1231   foreach c : check_funcs
1232     func = c.get(0)
1233     val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1234     required = c.get(1, {}).get('required', false)
1235     if required and not val
1236       error('openssl function @0@ is required'.format(func))
1237     elif not required
1238       cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1239     endif
1240   endforeach
1242   cdata.set('USE_OPENSSL', 1,
1243             description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1244   cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1245             description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1246 else
1247   ssl = not_found_dep
1248 endif
1252 ###############################################################
1253 # Library: uuid
1254 ###############################################################
1256 uuidopt = get_option('uuid')
1257 if uuidopt != 'none'
1258   uuidname = uuidopt.to_upper()
1259   if uuidopt == 'e2fs'
1260     uuid = dependency('uuid', required: true)
1261     uuidfunc = 'uuid_generate'
1262     uuidheader = 'uuid/uuid.h'
1263   elif uuidopt == 'bsd'
1264     # libc should have uuid function
1265     uuid = declare_dependency()
1266     uuidfunc = 'uuid_to_string'
1267     uuidheader = 'uuid.h'
1268   elif uuidopt == 'ossp'
1269     uuid = dependency('ossp-uuid', required: true)
1270     uuidfunc = 'uuid_export'
1271     uuidheader = 'ossp/uuid.h'
1272   else
1273     error('huh')
1274   endif
1276   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1277     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1278   endif
1279   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1281   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1282            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1283 else
1284   uuid = not_found_dep
1285 endif
1289 ###############################################################
1290 # Library: zlib
1291 ###############################################################
1293 zlibopt = get_option('zlib')
1294 zlib = not_found_dep
1295 if not zlibopt.disabled()
1296   zlib_t = dependency('zlib', required: zlibopt)
1298   if zlib_t.type_name() == 'internal'
1299     # if fallback was used, we don't need to test if headers are present (they
1300     # aren't built yet, so we can't test)
1301     zlib = zlib_t
1302   elif not zlib_t.found()
1303     warning('did not find zlib')
1304   elif not cc.has_header('zlib.h',
1305       args: test_c_args, include_directories: postgres_inc,
1306       dependencies: [zlib_t], required: zlibopt.enabled())
1307     warning('zlib header not found')
1308   elif not cc.has_type('z_streamp',
1309       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1310       args: test_c_args, include_directories: postgres_inc)
1311     if zlibopt.enabled()
1312       error('zlib version is too old')
1313     else
1314       warning('zlib version is too old')
1315     endif
1316   else
1317     zlib = zlib_t
1318   endif
1320   if zlib.found()
1321     cdata.set('HAVE_LIBZ', 1)
1322   endif
1323 endif
1327 ###############################################################
1328 # Library: tap test dependencies
1329 ###############################################################
1331 # Check whether tap tests are enabled or not
1332 tap_tests_enabled = false
1333 tapopt = get_option('tap_tests')
1334 if not tapopt.disabled()
1335   # Checking for perl modules for tap tests
1336   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1337   if perl_ipc_run_check.returncode() != 0
1338     message(perl_ipc_run_check.stderr().strip())
1339     if tapopt.enabled()
1340       error('Additional Perl modules are required to run TAP tests.')
1341     else
1342       warning('Additional Perl modules are required to run TAP tests.')
1343     endif
1344   else
1345     tap_tests_enabled = true
1346   endif
1347 endif
1351 ###############################################################
1352 # Library: zstd
1353 ###############################################################
1355 zstdopt = get_option('zstd')
1356 if not zstdopt.disabled()
1357   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1359   if zstd.found()
1360     cdata.set('USE_ZSTD', 1)
1361     cdata.set('HAVE_LIBZSTD', 1)
1362   endif
1364 else
1365   zstd = not_found_dep
1366 endif
1370 ###############################################################
1371 # Compiler tests
1372 ###############################################################
1374 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1375 # unnecessarily, because we optionally rely on newer features.
1376 c99_test = '''
1377 #include <stdbool.h>
1378 #include <complex.h>
1379 #include <tgmath.h>
1380 #include <inttypes.h>
1382 struct named_init_test {
1383   int a;
1384   int b;
1387 extern void structfunc(struct named_init_test);
1389 int main(int argc, char **argv)
1391   struct named_init_test nit = {
1392     .a = 3,
1393     .b = 5,
1394   };
1396   for (int loop_var = 0; loop_var < 3; loop_var++)
1397   {
1398     nit.a += nit.b;
1399   }
1401   structfunc((struct named_init_test){1, 0});
1403   return nit.a != 0;
1407 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1408   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1409         args: test_c_args + ['-std=c99'])
1410     test_c_args += '-std=c99'
1411     cflags += '-std=c99'
1412   else
1413     error('C compiler does not support C99')
1414   endif
1415 endif
1417 sizeof_long = cc.sizeof('long', args: test_c_args)
1418 cdata.set('SIZEOF_LONG', sizeof_long)
1419 if sizeof_long == 8
1420   cdata.set('HAVE_LONG_INT_64', 1)
1421   cdata.set('PG_INT64_TYPE', 'long int')
1422   cdata.set_quoted('INT64_MODIFIER', 'l')
1423 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1424   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1425   cdata.set('PG_INT64_TYPE', 'long long int')
1426   cdata.set_quoted('INT64_MODIFIER', 'll')
1427 else
1428   error('do not know how to get a 64bit int')
1429 endif
1431 if host_machine.endian() == 'big'
1432   cdata.set('WORDS_BIGENDIAN', 1)
1433 endif
1435 alignof_types = ['short', 'int', 'long', 'double']
1436 maxalign = 0
1437 foreach t : alignof_types
1438   align = cc.alignment(t, args: test_c_args)
1439   if maxalign < align
1440     maxalign = align
1441   endif
1442   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1443 endforeach
1444 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1446 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1447 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1450 # Check if __int128 is a working 128 bit integer type, and if so
1451 # define PG_INT128_TYPE to that typename.
1453 # This currently only detects a GCC/clang extension, but support for other
1454 # environments may be added in the future.
1456 # For the moment we only test for support for 128bit math; support for
1457 # 128bit literals and snprintf is not required.
1458 if cc.links('''
1459   /*
1460    * We don't actually run this test, just link it to verify that any support
1461    * functions needed for __int128 are present.
1462    *
1463    * These are globals to discourage the compiler from folding all the
1464    * arithmetic tests down to compile-time constants.  We do not have
1465    * convenient support for 128bit literals at this point...
1466    */
1467   __int128 a = 48828125;
1468   __int128 b = 97656250;
1470   int main(void)
1471   {
1472       __int128 c,d;
1473       a = (a << 12) + 1; /* 200000000001 */
1474       b = (b << 12) + 5; /* 400000000005 */
1475       /* try the most relevant arithmetic ops */
1476       c = a * b;
1477       d = (c + b) / b;
1478       /* must use the results, else compiler may optimize arithmetic away */
1479       return d != a+1;
1480   }''',
1481   name: '__int128',
1482   args: test_c_args)
1484   buggy_int128 = false
1486   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1487   # If not cross-compiling, we can test for bugs and disable use of __int128
1488   # with buggy compilers.  If cross-compiling, hope for the best.
1489   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1490   if not meson.is_cross_build()
1491     r = cc.run('''
1492     /* This must match the corresponding code in c.h: */
1493     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1494     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1495     #elif defined(_MSC_VER)
1496     #define pg_attribute_aligned(a) __declspec(align(a))
1497     #endif
1498     typedef __int128 int128a
1499     #if defined(pg_attribute_aligned)
1500     pg_attribute_aligned(8)
1501     #endif
1502     ;
1504     int128a holder;
1505     void pass_by_val(void *buffer, int128a par) { holder = par; }
1507     int main(void)
1508     {
1509         long int i64 = 97656225L << 12;
1510         int128a q;
1511         pass_by_val(main, (int128a) i64);
1512         q = (int128a) i64;
1513         return q != holder;
1514     }''',
1515     name: '__int128 alignment bug',
1516     args: test_c_args)
1517     assert(r.compiled())
1518     if r.returncode() != 0
1519       buggy_int128 = true
1520       message('__int128 support present but buggy and thus disabled')
1521     endif
1522   endif
1524   if not buggy_int128
1525     cdata.set('PG_INT128_TYPE', '__int128')
1526     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1527       alignment('__int128', args: test_c_args))
1528   endif
1529 endif
1532 # Check if the C compiler knows computed gotos (gcc extension, also
1533 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1535 # Checking whether computed gotos are supported syntax-wise ought to
1536 # be enough, as the syntax is otherwise illegal.
1537 if cc.compiles('''
1538     static inline int foo(void)
1539     {
1540       void *labeladdrs[] = {&&my_label};
1541       goto *labeladdrs[0];
1542       my_label:
1543       return 1;
1544     }''',
1545     args: test_c_args)
1546   cdata.set('HAVE_COMPUTED_GOTO', 1)
1547 endif
1550 # Check if the C compiler understands _Static_assert(),
1551 # and define HAVE__STATIC_ASSERT if so.
1553 # We actually check the syntax ({ _Static_assert(...) }), because we need
1554 # gcc-style compound expressions to be able to wrap the thing into macros.
1555 if cc.compiles('''
1556     int main(int arg, char **argv)
1557     {
1558         ({ _Static_assert(1, "foo"); });
1559     }
1560     ''',
1561     args: test_c_args)
1562   cdata.set('HAVE__STATIC_ASSERT', 1)
1563 endif
1566 # We use <stdbool.h> if we have it and it declares type bool as having
1567 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1568 if cc.has_type('_Bool', args: test_c_args) \
1569   and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1570   and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1571   cdata.set('HAVE__BOOL', 1)
1572   cdata.set('PG_USE_STDBOOL', 1)
1573 endif
1576 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1577 # warning for each use of %m.
1578 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1579 testsrc = '''
1580 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1581 static void call_log(void)
1583     emit_log(0, "error: %s: %m", "foo");
1586 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1587 foreach a : printf_attributes
1588   if cc.compiles(testsrc.format(a),
1589       args: test_c_args + attrib_error_args, name: 'format ' + a)
1590     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1591     break
1592   endif
1593 endforeach
1596 if cc.has_function_attribute('visibility:default') and \
1597   cc.has_function_attribute('visibility:hidden')
1598   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1600   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1601   # inlineshidden to C code as well... Any either way, we want to put these
1602   # flags into exported files (pgxs, .pc files).
1603   cflags_mod += '-fvisibility=hidden'
1604   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1605   ldflags_mod += '-fvisibility=hidden'
1606 endif
1609 # Check if various builtins exist. Some builtins are tested separately,
1610 # because we want to test something more complicated than the generic case.
1611 builtins = [
1612   'bswap16',
1613   'bswap32',
1614   'bswap64',
1615   'clz',
1616   'ctz',
1617   'constant_p',
1618   'frame_address',
1619   'popcount',
1620   'unreachable',
1623 foreach builtin : builtins
1624   fname = '__builtin_@0@'.format(builtin)
1625   if cc.has_function(fname, args: test_c_args)
1626     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1627   endif
1628 endforeach
1631 # Check if the C compiler understands __builtin_types_compatible_p,
1632 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1634 # We check usage with __typeof__, though it's unlikely any compiler would
1635 # have the former and not the latter.
1636 if cc.compiles('''
1637     static int x;
1638     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1639     ''',
1640     name: '__builtin_types_compatible_p',
1641     args: test_c_args)
1642   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1643 endif
1646 # Check if the C compiler understands __builtin_$op_overflow(),
1647 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1649 # Check for the most complicated case, 64 bit multiplication, as a
1650 # proxy for all of the operations.  To detect the case where the compiler
1651 # knows the function but library support is missing, we must link not just
1652 # compile, and store the results in global variables so the compiler doesn't
1653 # optimize away the call.
1654 if cc.links('''
1655     INT64 a = 1;
1656     INT64 b = 1;
1657     INT64 result;
1659     int main(void)
1660     {
1661         return __builtin_mul_overflow(a, b, &result);
1662     }''',
1663     name: '__builtin_mul_overflow',
1664     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1665     )
1666   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1667 endif
1670 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1671 # here. To prevent problems due to two detection methods working, stop
1672 # checking after one.
1673 if cc.links('''
1674     #include <cpuid.h>
1675     int main(int arg, char **argv)
1676     {
1677         unsigned int exx[4] = {0, 0, 0, 0};
1678         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1679     }
1680     ''', name: '__get_cpuid',
1681     args: test_c_args)
1682   cdata.set('HAVE__GET_CPUID', 1)
1683 elif cc.links('''
1684     #include <intrin.h>
1685     int main(int arg, char **argv)
1686     {
1687         unsigned int exx[4] = {0, 0, 0, 0};
1688         __cpuid(exx, 1);
1689     }
1690     ''', name: '__cpuid',
1691     args: test_c_args)
1692   cdata.set('HAVE__CPUID', 1)
1693 endif
1696 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1697 # versions of clang do not understand -fexcess-precision=standard, the use of
1698 # x87 floating point operations leads to problems like isinf possibly returning
1699 # false for a value that is infinite when converted from the 80bit register to
1700 # the 8byte memory representation.
1702 # Only perform the test if the compiler doesn't understand
1703 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1704 # automatically.
1705 if '-fexcess-precision=standard' not in cflags
1706   if not cc.compiles('''
1707 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1708 choke me
1709 #endif''',
1710       name: '', args: test_c_args)
1711     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1712   endif
1713 endif
1717 ###############################################################
1718 # Compiler flags
1719 ###############################################################
1721 common_functional_flags = [
1722   # Disable strict-aliasing rules; needed for gcc 3.3+
1723   '-fno-strict-aliasing',
1724   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1725   '-fwrapv',
1726   '-fexcess-precision=standard',
1729 cflags += cc.get_supported_arguments(common_functional_flags)
1730 if llvm.found()
1731   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1732 endif
1734 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1735 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1737 common_warning_flags = [
1738   '-Wmissing-prototypes',
1739   '-Wpointer-arith',
1740   # Really don't want VLAs to be used in our dialect of C
1741   '-Werror=vla',
1742   # On macOS, complain about usage of symbols newer than the deployment target
1743   '-Werror=unguarded-availability-new',
1744   '-Wendif-labels',
1745   '-Wmissing-format-attribute',
1746   '-Wimplicit-fallthrough=3',
1747   '-Wcast-function-type',
1748   '-Wshadow=compatible-local',
1749   # This was included in -Wall/-Wformat in older GCC versions
1750   '-Wformat-security',
1753 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1754 if llvm.found()
1755   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1756 endif
1758 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1759 # the result for them
1760 cflags_no_decl_after_statement = []
1761 if cc.has_argument('-Wdeclaration-after-statement')
1762   cflags_warn += '-Wdeclaration-after-statement'
1763   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1764 endif
1767 # The following tests want to suppress various unhelpful warnings by adding
1768 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1769 # switches, so we have to test for the positive form and if that works,
1770 # add the negative form.
1772 negative_warning_flags = [
1773   # Suppress clang's unhelpful unused-command-line-argument warnings.
1774   'unused-command-line-argument',
1776   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1777   # of warnings when building plperl because of usages in the Perl headers.
1778   'compound-token-split-by-macro',
1780   # Similarly disable useless truncation warnings from gcc 8+
1781   'format-truncation',
1782   'stringop-truncation',
1784   # Suppress clang 16's strict warnings about function casts
1785   'cast-function-type-strict',
1787   # To make warning_level=2 / -Wextra work, we'd need at least the following
1788   # 'clobbered',
1789   # 'missing-field-initializers',
1790   # 'sign-compare',
1791   # 'unused-parameter',
1794 foreach w : negative_warning_flags
1795   if cc.has_argument('-W' + w)
1796     cflags_warn += '-Wno-' + w
1797   endif
1798   if llvm.found() and cpp.has_argument('-W' + w)
1799     cxxflags_warn += '-Wno-' + w
1800   endif
1801 endforeach
1804 # From Project.pm
1805 if cc.get_id() == 'msvc'
1806   cflags_warn += [
1807     '/wd4018', # signed/unsigned mismatch
1808     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1809     '/wd4273', # inconsistent DLL linkage
1810     '/wd4101', # unreferenced local variable
1811     '/wd4102', # unreferenced label
1812     '/wd4090', # different 'modifier' qualifiers
1813     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1814   ]
1816   cppflags += [
1817     '/DWIN32',
1818     '/DWINDOWS',
1819     '/D__WINDOWS__',
1820     '/D__WIN32__',
1821     '/D_CRT_SECURE_NO_DEPRECATE',
1822     '/D_CRT_NONSTDC_NO_DEPRECATE',
1823   ]
1825   # We never need export libraries. As link.exe reports their creation, they
1826   # are unnecessarily noisy. Similarly, we don't need import library for
1827   # modules, we only import them dynamically, and they're also noisy.
1828   ldflags += '/NOEXP'
1829   ldflags_mod += '/NOIMPLIB'
1830 endif
1834 ###############################################################
1835 # Atomics
1836 ###############################################################
1838 if not get_option('spinlocks')
1839   warning('Not using spinlocks will cause poor performance')
1840 else
1841   cdata.set('HAVE_SPINLOCKS', 1)
1842 endif
1844 if not get_option('atomics')
1845   warning('Not using atomics will cause poor performance')
1846 else
1847   # XXX: perhaps we should require some atomics support in this case these
1848   # days?
1849   cdata.set('HAVE_ATOMICS', 1)
1851   atomic_checks = [
1852     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1853      'desc': '__sync_lock_test_and_set(char)',
1854      'test': '''
1855 char lock = 0;
1856 __sync_lock_test_and_set(&lock, 1);
1857 __sync_lock_release(&lock);'''},
1859     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1860      'desc': '__sync_lock_test_and_set(int32)',
1861      'test': '''
1862 int lock = 0;
1863 __sync_lock_test_and_set(&lock, 1);
1864 __sync_lock_release(&lock);'''},
1866     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1867      'desc': '__sync_val_compare_and_swap(int32)',
1868      'test': '''
1869 int val = 0;
1870 __sync_val_compare_and_swap(&val, 0, 37);'''},
1872     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1873      'desc': '__sync_val_compare_and_swap(int64)',
1874      'test': '''
1875 INT64 val = 0;
1876 __sync_val_compare_and_swap(&val, 0, 37);'''},
1878     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1879      'desc': ' __atomic_compare_exchange_n(int32)',
1880      'test': '''
1881 int val = 0;
1882 int expect = 0;
1883 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1885     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1886      'desc': ' __atomic_compare_exchange_n(int64)',
1887      'test': '''
1888 INT64 val = 0;
1889 INT64 expect = 0;
1890 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1891   ]
1893   foreach check : atomic_checks
1894     test = '''
1895 int main(void)
1898 }'''.format(check['test'])
1900     cdata.set(check['name'],
1901       cc.links(test,
1902         name: check['desc'],
1903         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1904     )
1905   endforeach
1907 endif
1911 ###############################################################
1912 # Select CRC-32C implementation.
1914 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1915 # use the special CRC instructions for calculating CRC-32C. If we're not
1916 # targeting such a processor, but we can nevertheless produce code that uses
1917 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1918 # implementations and select which one to use at runtime, depending on whether
1919 # SSE 4.2 is supported by the processor we're running on.
1921 # Similarly, if we are targeting an ARM processor that has the CRC
1922 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1923 # we're not targeting such a processor, but can nevertheless produce code that
1924 # uses the CRC instructions, compile both, and select at runtime.
1925 ###############################################################
1927 have_optimized_crc = false
1928 cflags_crc = []
1929 if host_cpu == 'x86' or host_cpu == 'x86_64'
1931   if cc.get_id() == 'msvc'
1932     cdata.set('USE_SSE42_CRC32C', false)
1933     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1934     have_optimized_crc = true
1935   else
1937     prog = '''
1938 #include <nmmintrin.h>
1940 int main(void)
1942     unsigned int crc = 0;
1943     crc = _mm_crc32_u8(crc, 0);
1944     crc = _mm_crc32_u32(crc, 0);
1945     /* return computed value, to prevent the above being optimized away */
1946     return crc == 0;
1950     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
1951           args: test_c_args)
1952       # Use Intel SSE 4.2 unconditionally.
1953       cdata.set('USE_SSE42_CRC32C', 1)
1954       have_optimized_crc = true
1955     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
1956           args: test_c_args + ['-msse4.2'])
1957       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
1958       # the runtime check.
1959       cflags_crc += '-msse4.2'
1960       cdata.set('USE_SSE42_CRC32C', false)
1961       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1962       have_optimized_crc = true
1963     endif
1965   endif
1967 elif host_cpu == 'arm' or host_cpu == 'aarch64'
1969   prog = '''
1970 #include <arm_acle.h>
1972 int main(void)
1974     unsigned int crc = 0;
1975     crc = __crc32cb(crc, 0);
1976     crc = __crc32ch(crc, 0);
1977     crc = __crc32cw(crc, 0);
1978     crc = __crc32cd(crc, 0);
1980     /* return computed value, to prevent the above being optimized away */
1981     return crc == 0;
1985   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
1986       args: test_c_args)
1987     # Use ARM CRC Extension unconditionally
1988     cdata.set('USE_ARMV8_CRC32C', 1)
1989     have_optimized_crc = true
1990   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
1991       args: test_c_args + ['-march=armv8-a+crc'])
1992     # Use ARM CRC Extension, with runtime check
1993     cflags_crc += '-march=armv8-a+crc'
1994     cdata.set('USE_ARMV8_CRC32C', false)
1995     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
1996     have_optimized_crc = true
1997   endif
1998 endif
2000 if not have_optimized_crc
2001   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2002   # support.
2003   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2004 endif
2008 ###############################################################
2009 # Other CPU specific stuff
2010 ###############################################################
2012 if host_cpu == 'x86_64'
2014   if cc.compiles('''
2015       void main(void)
2016       {
2017           long long x = 1; long long r;
2018           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2019       }''',
2020       name: '@0@: popcntq instruction'.format(host_cpu),
2021       args: test_c_args)
2022     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2023   endif
2025 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2026   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2027   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2028     if cc.compiles('''
2029       static inline int
2030       addi(int ra, int si)
2031       {
2032           int res = 0;
2033           if (__builtin_constant_p(si))
2034               __asm__ __volatile__(
2035                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2036           return res;
2037       }
2038       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2039       ''',
2040       args: test_c_args)
2041       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2042     endif
2043   endif
2044 endif
2048 ###############################################################
2049 # Library / OS tests
2050 ###############################################################
2052 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2053 # unnecessary checks over and over, particularly on windows.
2054 header_checks = [
2055   'atomic.h',
2056   'copyfile.h',
2057   'crtdefs.h',
2058   'execinfo.h',
2059   'getopt.h',
2060   'ifaddrs.h',
2061   'langinfo.h',
2062   'mbarrier.h',
2063   'stdbool.h',
2064   'strings.h',
2065   'sys/epoll.h',
2066   'sys/event.h',
2067   'sys/personality.h',
2068   'sys/prctl.h',
2069   'sys/procctl.h',
2070   'sys/signalfd.h',
2071   'sys/ucred.h',
2072   'termios.h',
2073   'ucred.h',
2076 foreach header : header_checks
2077   varname = 'HAVE_' + header.underscorify().to_upper()
2079   # Emulate autoconf behaviour of not-found->undef, found->1
2080   found = cc.has_header(header,
2081     include_directories: postgres_inc, args: test_c_args)
2082   cdata.set(varname, found ? 1 : false,
2083             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2084 endforeach
2087 decl_checks = [
2088   ['F_FULLFSYNC', 'fcntl.h'],
2089   ['fdatasync', 'unistd.h'],
2090   ['posix_fadvise', 'fcntl.h'],
2091   ['strlcat', 'string.h'],
2092   ['strlcpy', 'string.h'],
2093   ['strnlen', 'string.h'],
2096 # Need to check for function declarations for these functions, because
2097 # checking for library symbols wouldn't handle deployment target
2098 # restrictions on macOS
2099 decl_checks += [
2100   ['preadv', 'sys/uio.h'],
2101   ['pwritev', 'sys/uio.h'],
2104 foreach c : decl_checks
2105   func = c.get(0)
2106   header = c.get(1)
2107   args = c.get(2, {})
2108   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2110   found = cc.has_header_symbol(header, func,
2111     args: test_c_args, include_directories: postgres_inc,
2112     kwargs: args)
2113   cdata.set10(varname, found, description:
2114 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2115    don't.'''.format(func))
2116 endforeach
2119 if cc.has_type('struct cmsgcred',
2120     args: test_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? '' : '-DHAVE_SYS_UCRED_H'],
2121     include_directories: postgres_inc,
2122     prefix: '''
2123 #include <sys/socket.h>
2124 #include <sys/param.h>
2125 #ifdef HAVE_SYS_UCRED_H
2126 #include <sys/ucred.h>
2127 #endif''')
2128   cdata.set('HAVE_STRUCT_CMSGCRED', 1)
2129 else
2130   cdata.set('HAVE_STRUCT_CMSGCRED', false)
2131 endif
2133 if cc.has_type('struct option',
2134     args: test_c_args, include_directories: postgres_inc,
2135     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2136   cdata.set('HAVE_STRUCT_OPTION', 1)
2137 endif
2140 foreach c : ['opterr', 'optreset']
2141   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2143   if cc.links('''
2144 #include <unistd.h>
2145 int main(void)
2147     extern int @0@;
2148     @0@ = 1;
2150 '''.format(c), name: c, args: test_c_args)
2151     cdata.set(varname, 1)
2152   else
2153     cdata.set(varname, false)
2154   endif
2155 endforeach
2157 if cc.has_type('socklen_t',
2158     args: test_c_args, include_directories: postgres_inc,
2159     prefix: '''
2160 #include <sys/socket.h>''')
2161   cdata.set('HAVE_SOCKLEN_T', 1)
2162 endif
2164 if cc.has_member('struct sockaddr', 'sa_len',
2165     args: test_c_args, include_directories: postgres_inc,
2166     prefix: '''
2167 #include <sys/types.h>
2168 #include <sys/socket.h>''')
2169   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2170 endif
2172 if cc.has_member('struct tm', 'tm_zone',
2173     args: test_c_args, include_directories: postgres_inc,
2174     prefix: '''
2175 #include <sys/types.h>
2176 #include <time.h>
2177 ''')
2178   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2179 endif
2181 if cc.compiles('''
2182 #include <time.h>
2183 extern int foo(void);
2184 int foo(void)
2186     return timezone / 60;
2188 ''',
2189     name: 'global variable `timezone\' exists',
2190     args: test_c_args, include_directories: postgres_inc)
2191   cdata.set('HAVE_INT_TIMEZONE', 1)
2192 else
2193   cdata.set('HAVE_INT_TIMEZONE', false)
2194 endif
2196 if cc.has_type('union semun',
2197     args: test_c_args,
2198     include_directories: postgres_inc,
2199     prefix: '''
2200 #include <sys/types.h>
2201 #include <sys/ipc.h>
2202 #include <sys/sem.h>
2203 ''')
2204   cdata.set('HAVE_UNION_SEMUN', 1)
2205 endif
2207 if cc.compiles('''
2208 #include <string.h>
2209 int main(void)
2211   char buf[100];
2212   switch (strerror_r(1, buf, sizeof(buf)))
2213   { case 0: break; default: break; }
2214 }''',
2215     name: 'strerror_r',
2216     args: test_c_args, include_directories: postgres_inc)
2217   cdata.set('STRERROR_R_INT', 1)
2218 else
2219   cdata.set('STRERROR_R_INT', false)
2220 endif
2222 # Check for the locale_t type and find the right header file.  macOS
2223 # needs xlocale.h; standard is locale.h, but glibc also has an
2224 # xlocale.h file that we should not use.  MSVC has a replacement
2225 # defined in src/include/port/win32_port.h.
2226 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2227   cdata.set('HAVE_LOCALE_T', 1)
2228 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2229   cdata.set('HAVE_LOCALE_T', 1)
2230   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2231 elif cc.get_id() == 'msvc'
2232   cdata.set('HAVE_LOCALE_T', 1)
2233 endif
2235 # Check if the C compiler understands typeof or a variant.  Define
2236 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2237 foreach kw : ['typeof', '__typeof__', 'decltype']
2238   if cc.compiles('''
2239 int main(void)
2241     int x = 0;
2242     @0@(x) y;
2243     y = x;
2244     return y;
2246 '''.format(kw),
2247     name: 'typeof()',
2248     args: test_c_args, include_directories: postgres_inc)
2250     cdata.set('HAVE_TYPEOF', 1)
2251     if kw != 'typeof'
2252       cdata.set('typeof', kw)
2253     endif
2255     break
2256   endif
2257 endforeach
2260 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2261 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2262 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2263 wcstombs_l_test = '''
2264 #include <stdlib.h>
2265 #include <locale.h>
2268 void main(void)
2270 #ifndef wcstombs_l
2271     (void) wcstombs_l;
2272 #endif
2275 if (not cc.compiles(wcstombs_l_test.format(''),
2276       name: 'wcstombs_l') and
2277     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2278       name: 'wcstombs_l in xlocale.h'))
2279     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2280 endif
2283 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2284 # understands, because it conflicts with __declspec(restrict). Therefore we
2285 # define pg_restrict to the appropriate definition, which presumably won't
2286 # conflict.
2288 # We assume C99 support, so we don't need to make this conditional.
2290 # XXX: Historically we allowed platforms to disable restrict in template
2291 # files, but that was only added for AIX when building with XLC, which we
2292 # don't support yet.
2293 cdata.set('pg_restrict', '__restrict')
2296 # Most libraries are included only if they demonstrably provide a function we
2297 # need, but libm is an exception: always include it, because there are too
2298 # many compilers that play cute optimization games that will break probes for
2299 # standard functions such as pow().
2300 os_deps += cc.find_library('m', required: false)
2302 rt_dep = cc.find_library('rt', required: false)
2304 dl_dep = cc.find_library('dl', required: false)
2306 util_dep = cc.find_library('util', required: false)
2307 posix4_dep = cc.find_library('posix4', required: false)
2309 getopt_dep = cc.find_library('getopt', required: false)
2310 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2311 # Check if we want to replace getopt/getopt_long even if provided by the system
2312 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2313 #   so always use our version on Windows
2314 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2315 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2316 # - We want to use system's getopt_long() only if the system provides struct
2317 #   option
2318 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2319 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2321 # Required on BSDs
2322 execinfo_dep = cc.find_library('execinfo', required: false)
2324 if host_system == 'cygwin'
2325   cygipc_dep = cc.find_library('cygipc', required: false)
2326 else
2327   cygipc_dep = not_found_dep
2328 endif
2330 if host_system == 'sunos'
2331   socket_dep = cc.find_library('socket', required: false)
2332 else
2333   socket_dep = not_found_dep
2334 endif
2336 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2337 # unnecessary checks over and over, particularly on windows.
2338 func_checks = [
2339   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2340   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2341   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2342   ['copyfile'],
2343   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2344   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2345   # required. Just checking for dlsym() ought to suffice.
2346   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2347   ['explicit_bzero'],
2348   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2349   ['getifaddrs'],
2350   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2351   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2352   ['getpeereid'],
2353   ['getpeerucred'],
2354   ['inet_aton'],
2355   ['inet_pton'],
2356   ['kqueue'],
2357   ['mbstowcs_l'],
2358   ['memset_s'],
2359   ['mkdtemp'],
2360   ['posix_fadvise'],
2361   ['posix_fallocate'],
2362   ['ppoll'],
2363   ['pstat'],
2364   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2365   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2366   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2367   ['setproctitle', {'dependencies': [util_dep]}],
2368   ['setproctitle_fast'],
2369   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2370   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2371   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2372   ['socket', {'dependencies': [socket_dep], 'define': false}],
2373   ['strchrnul'],
2374   ['strerror_r', {'dependencies': [thread_dep]}],
2375   ['strlcat'],
2376   ['strlcpy'],
2377   ['strnlen'],
2378   ['strsignal'],
2379   ['sync_file_range'],
2380   ['syncfs'],
2381   ['uselocale'],
2382   ['wcstombs_l'],
2385 func_check_results = {}
2386 foreach c : func_checks
2387   func = c.get(0)
2388   kwargs = c.get(1, {})
2389   deps = kwargs.get('dependencies', [])
2391   if kwargs.get('skip', false)
2392     continue
2393   endif
2395   found = cc.has_function(func, args: test_c_args)
2397   if not found
2398     foreach dep : deps
2399       if not dep.found()
2400         continue
2401       endif
2402       found = cc.has_function(func, args: test_c_args,
2403                               dependencies: [dep])
2404       if found
2405         os_deps += dep
2406         break
2407       endif
2408     endforeach
2409   endif
2411   func_check_results += {func: found}
2413   if kwargs.get('define', true)
2414     # Emulate autoconf behaviour of not-found->undef, found->1
2415     cdata.set('HAVE_' + func.underscorify().to_upper(),
2416               found  ? 1 : false,
2417               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2418   endif
2419 endforeach
2422 if cc.has_function('syslog', args: test_c_args) and \
2423     cc.check_header('syslog.h', args: test_c_args)
2424   cdata.set('HAVE_SYSLOG', 1)
2425 endif
2428 # MSVC has replacements defined in src/include/port/win32_port.h.
2429 if cc.get_id() == 'msvc'
2430   cdata.set('HAVE_WCSTOMBS_L', 1)
2431   cdata.set('HAVE_MBSTOWCS_L', 1)
2432 endif
2435 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2436 # semaphores
2437 if sema_kind == 'unnamed_posix' and \
2438    not func_check_results.get('sem_init', false)
2439   sema_kind = 'sysv'
2440 endif
2442 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2443 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2445 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2446 cdata.set_quoted('DLSUFFIX', dlsuffix)
2449 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2450 cdata.set_quoted('PG_VERSION_STR',
2451   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2452     pg_version, host_machine.cpu_family(), host_system,
2453     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2454   )
2459 ###############################################################
2460 # Threading
2461 ###############################################################
2463 # XXX: About to rely on thread safety in the autoconf build, so not worth
2464 # implementing a fallback.
2465 cdata.set('ENABLE_THREAD_SAFETY', 1)
2469 ###############################################################
2470 # NLS / Gettext
2471 ###############################################################
2473 nlsopt = get_option('nls')
2474 libintl = not_found_dep
2476 if not nlsopt.disabled()
2477   # otherwise there'd be lots of
2478   # "Gettext not found, all translation (po) targets will be ignored."
2479   # warnings if not found.
2480   msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2482   # meson 0.59 has this wrapped in dependency('int')
2483   if (msgfmt.found() and
2484       cc.check_header('libintl.h', required: nlsopt,
2485         args: test_c_args, include_directories: postgres_inc))
2487     # in libc
2488     if cc.has_function('ngettext')
2489       libintl = declare_dependency()
2490     else
2491       libintl = cc.find_library('intl',
2492         has_headers: ['libintl.h'], required: nlsopt,
2493         header_include_directories: postgres_inc,
2494         dirs: test_lib_d)
2495     endif
2496   endif
2498   if libintl.found()
2499     i18n = import('i18n')
2500     cdata.set('ENABLE_NLS', 1)
2501   endif
2502 endif
2506 ###############################################################
2507 # Build
2508 ###############################################################
2510 # Set up compiler / linker arguments to be used everywhere, individual targets
2511 # can add further args directly, or indirectly via dependencies
2512 add_project_arguments(cflags, language: ['c'])
2513 add_project_arguments(cppflags, language: ['c'])
2514 add_project_arguments(cflags_warn, language: ['c'])
2515 add_project_arguments(cxxflags, language: ['cpp'])
2516 add_project_arguments(cppflags, language: ['cpp'])
2517 add_project_arguments(cxxflags_warn, language: ['cpp'])
2518 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2521 # Collect a number of lists of things while recursing through the source
2522 # tree. Later steps then can use those.
2524 # list of targets for various alias targets
2525 backend_targets = []
2526 bin_targets = []
2527 pl_targets = []
2528 contrib_targets = []
2529 testprep_targets = []
2532 # Define the tests to distribute them to the correct test styles later
2533 test_deps = []
2534 tests = []
2537 # Default options for targets
2539 # First identify rpaths
2540 bin_install_rpaths = []
2541 lib_install_rpaths = []
2542 mod_install_rpaths = []
2545 # Don't add rpaths on darwin for now - as long as only absolute references to
2546 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2547 # their final destination.
2548 if host_system != 'darwin'
2549   # Add absolute path to libdir to rpath. This ensures installed binaries /
2550   # libraries find our libraries (mainly libpq).
2551   bin_install_rpaths += dir_prefix / dir_lib
2552   lib_install_rpaths += dir_prefix / dir_lib
2553   mod_install_rpaths += dir_prefix / dir_lib
2555   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2556   #
2557   # Not needed on darwin even if we use relative rpaths for our own libraries,
2558   # as the install_name of libraries in extra_lib_dirs will point to their
2559   # location anyway.
2560   bin_install_rpaths += postgres_lib_d
2561   lib_install_rpaths += postgres_lib_d
2562   mod_install_rpaths += postgres_lib_d
2563 endif
2566 # Define arguments for default targets
2568 default_target_args = {
2569   'implicit_include_directories': false,
2570   'install': true,
2573 default_lib_args = default_target_args + {
2574   'name_prefix': '',
2577 internal_lib_args = default_lib_args + {
2578   'build_by_default': false,
2579   'install': false,
2582 default_mod_args = default_lib_args + {
2583   'name_prefix': '',
2584   'install_dir': dir_lib_pkg,
2587 default_bin_args = default_target_args + {
2588   'install_dir': dir_bin,
2591 if get_option('rpath')
2592   default_lib_args += {
2593     'install_rpath': ':'.join(lib_install_rpaths),
2594   }
2596   default_mod_args += {
2597     'install_rpath': ':'.join(mod_install_rpaths),
2598   }
2600   default_bin_args += {
2601     'install_rpath': ':'.join(bin_install_rpaths),
2602   }
2603 endif
2606 # Helper for exporting a limited number of symbols
2607 gen_export_kwargs = {
2608   'input': 'exports.txt',
2609   'output': '@BASENAME@.'+export_file_suffix,
2610   'command': [perl, files('src/tools/gen_export.pl'),
2611    '--format', export_file_format,
2612    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2613   'build_by_default': false,
2614   'install': false,
2620 ### windows resources related stuff
2623 if host_system == 'windows'
2624   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2625   win32ver_rc = files('src/port/win32ver.rc')
2626   rcgen = find_program('src/tools/rcgen', native: true)
2628   rcgen_base_args = [
2629     '--srcdir', '@SOURCE_DIR@',
2630     '--builddir', meson.build_root(),
2631     '--rcout', '@OUTPUT0@',
2632     '--out', '@OUTPUT1@',
2633     '--input', '@INPUT@',
2634     '@EXTRA_ARGS@',
2635   ]
2637   if cc.get_argument_syntax() == 'msvc'
2638     rc = find_program('rc', required: true)
2639     rcgen_base_args += ['--rc', rc.path()]
2640     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2641   else
2642     windres = find_program('windres', required: true)
2643     rcgen_base_args += ['--windres', windres.path()]
2644     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2645   endif
2647   # msbuild backend doesn't support this atm
2648   if meson.backend() == 'ninja'
2649     rcgen_base_args += ['--depfile', '@DEPFILE@']
2650   endif
2652   rcgen_bin_args = rcgen_base_args + [
2653     '--VFT_TYPE', 'VFT_APP',
2654     '--FILEENDING', 'exe',
2655     '--ICO', pg_ico
2656   ]
2658   rcgen_lib_args = rcgen_base_args + [
2659     '--VFT_TYPE', 'VFT_DLL',
2660     '--FILEENDING', 'dll',
2661   ]
2663   rc_bin_gen = generator(rcgen,
2664     depfile: '@BASENAME@.d',
2665     arguments: rcgen_bin_args,
2666     output: rcgen_outputs,
2667   )
2669   rc_lib_gen = generator(rcgen,
2670     depfile: '@BASENAME@.d',
2671     arguments: rcgen_lib_args,
2672     output: rcgen_outputs,
2673   )
2674 endif
2678 # headers that the whole build tree depends on
2679 generated_headers = []
2680 # headers that the backend build depends on
2681 generated_backend_headers = []
2682 # configure_files() output, needs a way of converting to file names
2683 configure_files = []
2685 # generated files that might conflict with a partial in-tree autoconf build
2686 generated_sources = []
2687 # same, for paths that differ between autoconf / meson builds
2688 # elements are [dir, [files]]
2689 generated_sources_ac = {}
2692 # First visit src/include - all targets creating headers are defined
2693 # within. That makes it easy to add the necessary dependencies for the
2694 # subsequent build steps.
2696 subdir('src/include')
2698 subdir('config')
2700 # Then through src/port and src/common, as most other things depend on them
2702 frontend_port_code = declare_dependency(
2703   compile_args: ['-DFRONTEND'],
2704   include_directories: [postgres_inc],
2705   dependencies: os_deps,
2708 backend_port_code = declare_dependency(
2709   compile_args: ['-DBUILDING_DLL'],
2710   include_directories: [postgres_inc],
2711   sources: [errcodes], # errcodes.h is needed due to use of ereport
2712   dependencies: os_deps,
2715 subdir('src/port')
2717 frontend_common_code = declare_dependency(
2718   compile_args: ['-DFRONTEND'],
2719   include_directories: [postgres_inc],
2720   sources: generated_headers,
2721   dependencies: [os_deps, zlib, zstd],
2724 backend_common_code = declare_dependency(
2725   compile_args: ['-DBUILDING_DLL'],
2726   include_directories: [postgres_inc],
2727   sources: generated_headers,
2728   dependencies: [os_deps, zlib, zstd],
2731 subdir('src/common')
2733 # all shared libraries should depend on shlib_code
2734 shlib_code = declare_dependency(
2735   link_args: ldflags_sl,
2738 # all static libraries not part of the backend should depend on this
2739 frontend_stlib_code = declare_dependency(
2740   include_directories: [postgres_inc],
2741   link_with: [common_static, pgport_static],
2742   sources: generated_headers,
2743   dependencies: [os_deps, libintl],
2746 # all shared libraries not part of the backend should depend on this
2747 frontend_shlib_code = declare_dependency(
2748   include_directories: [postgres_inc],
2749   link_with: [common_shlib, pgport_shlib],
2750   sources: generated_headers,
2751   dependencies: [shlib_code, os_deps, libintl],
2754 # Dependencies both for static and shared libpq
2755 libpq_deps += [
2756   thread_dep,
2758   gssapi,
2759   ldap_r,
2760   libintl,
2761   ssl,
2764 subdir('src/interfaces/libpq')
2765 # fe_utils depends on libpq
2766 subdir('src/fe_utils')
2768 # for frontend binaries
2769 frontend_code = declare_dependency(
2770   include_directories: [postgres_inc],
2771   link_with: [fe_utils, common_static, pgport_static],
2772   sources: generated_headers,
2773   dependencies: [os_deps, libintl],
2776 backend_both_deps += [
2777   thread_dep,
2778   bsd_auth,
2779   gssapi,
2780   icu,
2781   icu_i18n,
2782   ldap,
2783   libintl,
2784   libxml,
2785   lz4,
2786   pam,
2787   ssl,
2788   systemd,
2789   zlib,
2790   zstd,
2793 backend_mod_deps = backend_both_deps + os_deps
2795 backend_code = declare_dependency(
2796   compile_args: ['-DBUILDING_DLL'],
2797   include_directories: [postgres_inc],
2798   link_args: ldflags_be,
2799   link_with: [],
2800   sources: generated_headers + generated_backend_headers,
2801   dependencies: os_deps + backend_both_deps + backend_deps,
2804 # install these files only during test, not main install
2805 test_install_data = []
2806 test_install_libs = []
2808 # src/backend/meson.build defines backend_mod_code used for extension
2809 # libraries.
2812 # Then through the main sources. That way contrib can have dependencies on
2813 # main sources. Note that this explicitly doesn't enter src/test, right now a
2814 # few regression tests depend on contrib files.
2816 subdir('src')
2818 subdir('contrib')
2820 subdir('src/test')
2821 subdir('src/interfaces/libpq/test')
2822 subdir('src/interfaces/ecpg/test')
2824 subdir('doc/src/sgml')
2826 generated_sources_ac += {'': ['GNUmakefile']}
2828 # After processing src/test, add test_install_libs to the testprep_targets
2829 # to build them
2830 testprep_targets += test_install_libs
2833 # If there are any files in the source directory that we also generate in the
2834 # build directory, they might get preferred over the newly generated files,
2835 # e.g. because of a #include "file", which always will search in the current
2836 # directory first.
2837 message('checking for file conflicts between source and build directory')
2838 conflicting_files = []
2839 potentially_conflicting_files_t = []
2840 potentially_conflicting_files_t += generated_headers
2841 potentially_conflicting_files_t += generated_backend_headers
2842 potentially_conflicting_files_t += generated_backend_sources
2843 potentially_conflicting_files_t += generated_sources
2845 potentially_conflicting_files = []
2847 # convert all sources of potentially conflicting files into uniform shape
2848 foreach t : potentially_conflicting_files_t
2849   potentially_conflicting_files += t.full_path()
2850 endforeach
2851 foreach t : configure_files
2852   t = '@0@'.format(t)
2853   potentially_conflicting_files += meson.current_build_dir() / t
2854 endforeach
2855 foreach sub, fnames : generated_sources_ac
2856   sub = meson.build_root() / sub
2857   foreach fname : fnames
2858     potentially_conflicting_files += sub / fname
2859   endforeach
2860 endforeach
2862 # find and report conflicting files
2863 foreach build_path : potentially_conflicting_files
2864   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2865   # str.replace is in 0.56
2866   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2867   if fs.exists(src_path) or fs.is_symlink(src_path)
2868     conflicting_files += src_path
2869   endif
2870 endforeach
2871 # XXX: Perhaps we should generate a file that would clean these up? The list
2872 # can be long.
2873 if conflicting_files.length() > 0
2874   errmsg_cleanup = '''
2875 Conflicting files in source directory:
2876   @0@
2878 The conflicting files need to be removed, either by removing the files listed
2879 above, or by running configure and then make maintainer-clean.
2881   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2882   error(errmsg_nonclean_base.format(errmsg_cleanup))
2883 endif
2887 ###############################################################
2888 # Test prep
2889 ###############################################################
2891 # DESTDIR for the installation we'll run tests in
2892 test_install_destdir = meson.build_root() / 'tmp_install/'
2894 # DESTDIR + prefix appropriately munged
2895 if build_system != 'windows'
2896   # On unixoid systems this is trivial, we just prepend the destdir
2897   assert(dir_prefix.startswith('/')) # enforced by meson
2898   test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
2899 else
2900   # drives, drive-relative paths, etc make this complicated on windows, call
2901   # into a copy of meson's logic for it
2902   command = [
2903     python, '-c',
2904     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
2905     test_install_destdir, dir_prefix]
2906   test_install_location = run_command(command, check: true).stdout().strip()
2907 endif
2909 meson_install_args = meson_args + ['install'] + {
2910     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
2911     'muon': []
2912 }[meson_impl]
2914 # setup tests should  be run first,
2915 # so define priority for these
2916 setup_tests_priority = 100
2917 test('tmp_install',
2918     meson_bin, args: meson_install_args ,
2919     env: {'DESTDIR':test_install_destdir},
2920     priority: setup_tests_priority,
2921     timeout: 300,
2922     is_parallel: false,
2923     suite: ['setup'])
2925 # get full paths of test_install_libs to copy them
2926 test_install_libs_fp = []
2927 foreach lib: test_install_libs
2928   test_install_libs_fp += lib.full_path()
2929 endforeach
2931 install_test_files = files('src/tools/install_test_files')
2932 test('install_test_files',
2933     python, args: [
2934       install_test_files,
2935       '--datadir', test_install_location / contrib_data_args['install_dir'],
2936       '--libdir', test_install_location / dir_lib_pkg,
2937       '--install-data', test_install_data,
2938       '--install-libs', test_install_libs_fp,
2939     ],
2940     priority: setup_tests_priority,
2941     is_parallel: false,
2942     suite: ['setup'])
2944 test_result_dir = meson.build_root() / 'testrun'
2947 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
2948 # inevitable conflicts from running tests in parallel, hackishly assign
2949 # different ports for different tests.
2951 testport = 40000
2953 test_env = environment()
2955 temp_install_bindir = test_install_location / get_option('bindir')
2956 test_env.set('PG_REGRESS', pg_regress.full_path())
2957 test_env.set('REGRESS_SHLIB', regress_module.full_path())
2959 # Test suites that are not safe by default but can be run if selected
2960 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
2961 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
2962 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
2964 # Add the temporary installation to the library search path on platforms where
2965 # that works (everything but windows, basically). On windows everything
2966 # library-like gets installed into bindir, solving that issue.
2967 if library_path_var != ''
2968   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
2969 endif
2973 ###############################################################
2974 # Test Generation
2975 ###############################################################
2977 # When using a meson version understanding exclude_suites, define a
2978 # 'tmp_install' test setup (the default) that excludes tests running against a
2979 # pre-existing install and a 'running' setup that conflicts with creation of
2980 # the temporary installation and tap tests (which don't support running
2981 # against a running server).
2983 running_suites = []
2984 install_suites = []
2985 if meson.version().version_compare('>=0.57')
2986   runningcheck = true
2987 else
2988   runningcheck = false
2989 endif
2991 testwrap = files('src/tools/testwrap')
2993 foreach test_dir : tests
2994   testwrap_base = [
2995     testwrap,
2996     '--basedir', meson.build_root(),
2997     '--srcdir', test_dir['sd'],
2998   ]
3000   foreach kind, v : test_dir
3001     if kind in ['sd', 'bd', 'name']
3002       continue
3003     endif
3005     t = test_dir[kind]
3007     if kind in ['regress', 'isolation', 'ecpg']
3008       if kind == 'regress'
3009         runner = pg_regress
3010         fallback_dbname = 'regression_@0@'
3011       elif kind == 'isolation'
3012         runner = pg_isolation_regress
3013         fallback_dbname = 'isolation_regression_@0@'
3014       elif kind == 'ecpg'
3015         runner = pg_regress_ecpg
3016         fallback_dbname = 'ecpg_regression_@0@'
3017       endif
3019       test_group = test_dir['name']
3020       test_group_running = test_dir['name'] + '-running'
3022       test_output = test_result_dir / test_group / kind
3023       test_output_running = test_result_dir / test_group_running/ kind
3025       # Unless specified by the test, choose a non-conflicting database name,
3026       # to avoid conflicts when running against existing server.
3027       dbname = t.get('dbname',
3028         fallback_dbname.format(test_dir['name']))
3030       test_command_base = [
3031         runner.full_path(),
3032         '--inputdir', t.get('inputdir', test_dir['sd']),
3033         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3034         '--bindir', '',
3035         '--dlpath', test_dir['bd'],
3036         '--max-concurrent-tests=20',
3037         '--dbname', dbname,
3038       ] + t.get('regress_args', [])
3040       test_selection = []
3041       if t.has_key('schedule')
3042         test_selection += ['--schedule', t['schedule'],]
3043       endif
3045       if kind == 'isolation'
3046         test_selection += t.get('specs', [])
3047       else
3048         test_selection += t.get('sql', [])
3049       endif
3051       env = test_env
3052       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3054       test_kwargs = {
3055         'priority': 10,
3056         'timeout': 1000,
3057         'depends': test_deps + t.get('deps', []),
3058         'env': env,
3059       } + t.get('test_kwargs', {})
3061       test(test_group / kind,
3062         python,
3063         args: [
3064           testwrap_base,
3065           '--testgroup', test_group,
3066           '--testname', kind,
3067           '--',
3068           test_command_base,
3069           '--outputdir', test_output,
3070           '--temp-instance', test_output / 'tmp_check',
3071           '--port', testport.to_string(),
3072           test_selection,
3073         ],
3074         suite: test_group,
3075         kwargs: test_kwargs,
3076       )
3077       install_suites += test_group
3079       # some tests can't support running against running DB
3080       if runningcheck and t.get('runningcheck', true)
3081         test(test_group_running / kind,
3082           python,
3083           args: [
3084             testwrap_base,
3085             '--testgroup', test_group_running,
3086             '--testname', kind,
3087             '--',
3088             test_command_base,
3089             '--outputdir', test_output_running,
3090             test_selection,
3091           ],
3092           is_parallel: t.get('runningcheck-parallel', true),
3093           suite: test_group_running,
3094           kwargs: test_kwargs,
3095         )
3096         running_suites += test_group_running
3097       endif
3099       testport += 1
3100     elif kind == 'tap'
3101       if not tap_tests_enabled
3102         continue
3103       endif
3105       test_command = [
3106         perl.path(),
3107         '-I', meson.source_root() / 'src/test/perl',
3108         '-I', test_dir['sd'],
3109       ]
3111       # Add temporary install, the build directory for non-installed binaries and
3112       # also test/ for non-installed test binaries built separately.
3113       env = test_env
3114       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3116       foreach name, value : t.get('env', {})
3117         env.set(name, value)
3118       endforeach
3120       test_group = test_dir['name']
3121       test_kwargs = {
3122         'protocol': 'tap',
3123         'suite': test_group,
3124         'timeout': 1000,
3125         'depends': test_deps + t.get('deps', []),
3126         'env': env,
3127       } + t.get('test_kwargs', {})
3129       foreach onetap : t['tests']
3130         # Make tap test names prettier, remove t/ and .pl
3131         onetap_p = onetap
3132         if onetap_p.startswith('t/')
3133           onetap_p = onetap.split('t/')[1]
3134         endif
3135         if onetap_p.endswith('.pl')
3136           onetap_p = fs.stem(onetap_p)
3137         endif
3139         test(test_dir['name'] / onetap_p,
3140           python,
3141           kwargs: test_kwargs,
3142           args: testwrap_base + [
3143             '--testgroup', test_dir['name'],
3144             '--testname', onetap_p,
3145             '--', test_command,
3146             test_dir['sd'] / onetap,
3147           ],
3148         )
3149       endforeach
3150       install_suites += test_group
3151     else
3152       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3153     endif
3155   endforeach # kinds of tests
3157 endforeach # directories with tests
3159 # repeat condition so meson realizes version dependency
3160 if meson.version().version_compare('>=0.57')
3161   add_test_setup('tmp_install',
3162     is_default: true,
3163     exclude_suites: running_suites)
3164   add_test_setup('running',
3165     exclude_suites: ['setup'] + install_suites)
3166 endif
3169 ###############################################################
3170 # Pseudo targets
3171 ###############################################################
3173 alias_target('backend', backend_targets)
3174 alias_target('bin', bin_targets + [libpq_st])
3175 alias_target('pl', pl_targets)
3176 alias_target('contrib', contrib_targets)
3177 alias_target('testprep', testprep_targets)
3181 ###############################################################
3182 # The End, The End, My Friend
3183 ###############################################################
3185 if meson.version().version_compare('>=0.57')
3187   summary(
3188     {
3189       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3190       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3191       'segment size': get_option('segsize_blocks') != 0 ?
3192         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3193         '@0@ GB'.format(get_option('segsize')),
3194     },
3195     section: 'Data layout',
3196   )
3198   summary(
3199     {
3200       'host system': '@0@ @1@'.format(host_system, host_cpu),
3201       'build system': '@0@ @1@'.format(build_machine.system(),
3202                                        build_machine.cpu_family()),
3203     },
3204     section: 'System',
3205   )
3207   summary(
3208     {
3209       'linker': '@0@'.format(cc.get_linker_id()),
3210       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3211     },
3212     section: 'Compiler',
3213   )
3215   summary(
3216     {
3217       'CPP FLAGS': ' '.join(cppflags),
3218       'C FLAGS, functional': ' '.join(cflags),
3219       'C FLAGS, warnings': ' '.join(cflags_warn),
3220       'C FLAGS, modules': ' '.join(cflags_mod),
3221       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3222       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3223     },
3224     section: 'Compiler Flags',
3225   )
3227   if llvm.found()
3228     summary(
3229       {
3230         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3231       },
3232       section: 'Compiler',
3233     )
3235     summary(
3236       {
3237         'C++ FLAGS, functional': ' '.join(cxxflags),
3238         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3239         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3240       },
3241       section: 'Compiler Flags',
3242     )
3243   endif
3245   summary(
3246     {
3247       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3248       'dtrace': dtrace,
3249     },
3250     section: 'Programs',
3251   )
3253   summary(
3254     {
3255       'bonjour': bonjour,
3256       'bsd_auth': bsd_auth,
3257       'gss': gssapi,
3258       'icu': icu,
3259       'ldap': ldap,
3260       'libxml': libxml,
3261       'libxslt': libxslt,
3262       'llvm': llvm,
3263       'lz4': lz4,
3264       'nls': libintl,
3265       'pam': pam,
3266       'plperl': perl_dep,
3267       'plpython': python3_dep,
3268       'pltcl': tcl_dep,
3269       'readline': readline,
3270       'selinux': selinux,
3271       'ssl': ssl,
3272       'systemd': systemd,
3273       'uuid': uuid,
3274       'zlib': zlib,
3275       'zstd': zstd,
3276     },
3277     section: 'External libraries',
3278   )
3280 endif