Improve locking around InjectionPointRun()
[pgsql.git] / meson.build
blobf454160e86e1ae691374913cbab2cd74c9549171
1 # Copyright (c) 2022-2024, 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: '17beta2',
12   license: 'PostgreSQL',
14   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
15   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
16   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
17   meson_version: '>=0.54',
18   default_options: [
19     'warning_level=1', #-Wall equivalent
20     'b_pch=false',
21     'buildtype=debugoptimized', # -O2 + debug
22     # For compatibility with the autoconf build, set a default prefix. This
23     # works even on windows, where it's a drive-relative path (i.e. when on
24     # d:/somepath it'll install to d:/usr/local/pgsql)
25     'prefix=/usr/local/pgsql',
26   ]
31 ###############################################################
32 # Basic prep
33 ###############################################################
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
42 cc = meson.get_compiler('c')
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
46 auto_features = get_option('auto_features')
50 ###############################################################
51 # Safety first
52 ###############################################################
54 # It's very easy to get into confusing states when the source directory
55 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
56 # refuse to build in that case.
58 # There's a more elaborate check later, that checks for conflicts around all
59 # generated files. But we can only do that much further down the line, so this
60 # quick check seems worth it. Adhering to this advice should clean up the
61 # conflict, but won't protect against somebody doing make distclean or just
62 # removing pg_config.h
63 errmsg_nonclean_base = '''
64 ****
65 Non-clean source code directory detected.
67 To build with meson the source tree may not have an in-place, ./configure
68 style, build configured. You can have both meson and ./configure style builds
69 for the same source tree by building out-of-source / VPATH with
70 configure. Alternatively use a separate check out for meson based builds.
72 @0@
73 ****'''
74 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
75   errmsg_cleanup = 'To clean up, run make distclean in the source tree.'
76   error(errmsg_nonclean_base.format(errmsg_cleanup))
77 endif
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
88 postgres_lib_d = get_option('extra_lib_dirs')
90 cppflags = []
92 cflags = []
93 cxxflags = []
94 cflags_warn = []
95 cxxflags_warn = []
96 cflags_mod = []
97 cxxflags_mod = []
99 ldflags = []
100 ldflags_be = []
101 ldflags_sl = []
102 ldflags_mod = []
104 test_c_args = []
106 os_deps = []
107 backend_both_deps = []
108 backend_deps = []
109 libpq_deps = []
111 pg_sysroot = ''
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
122 pg_version = meson.project_version()
124 if pg_version.endswith('devel')
125   pg_version_arr = [pg_version.split('devel')[0], '0']
126 elif pg_version.contains('beta')
127   pg_version_arr = [pg_version.split('beta')[0], '0']
128 elif pg_version.contains('rc')
129   pg_version_arr = [pg_version.split('rc')[0], '0']
130 else
131   pg_version_arr = pg_version.split('.')
132 endif
134 pg_version_major = pg_version_arr[0].to_int()
135 pg_version_minor = pg_version_arr[1].to_int()
136 pg_version_num = (pg_version_major * 10000) + pg_version_minor
138 pg_url = 'https://www.postgresql.org/'
140 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
141 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
142 cdata.set_quoted('PACKAGE_URL', pg_url)
143 cdata.set_quoted('PACKAGE_VERSION', pg_version)
144 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
145 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
147 pg_version += get_option('extra_version')
148 cdata.set_quoted('PG_VERSION', pg_version)
149 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
150 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
151 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
152 cdata.set('PG_VERSION_NUM', pg_version_num)
153 # PG_VERSION_STR is built later, it depends on compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 exesuffix = '' # overridden below where necessary
163 dlsuffix = '.so' # overridden below where necessary
164 library_path_var = 'LD_LIBRARY_PATH'
166 # Format of file to control exports from libraries, and how to pass them to
167 # the compiler. For export_fmt @0@ is the path to the file export file.
168 export_file_format = 'gnu'
169 export_file_suffix = 'list'
170 export_fmt = '-Wl,--version-script=@0@'
172 # Flags to add when linking a postgres extension, @0@ is path to
173 # the relevant object on the platform.
174 mod_link_args_fmt = []
176 memset_loop_limit = 1024
178 # Choice of shared memory and semaphore implementation
179 shmem_kind = 'sysv'
180 sema_kind = 'sysv'
182 # We implement support for some operating systems by pretending they're
183 # another. Map here, before determining system properties below
184 if host_system == 'dragonfly'
185   # apparently the most similar
186   host_system = 'netbsd'
187 elif host_system == 'android'
188   # while android isn't quite a normal linux, it seems close enough
189   # for our purposes so far
190   host_system = 'linux'
191 endif
193 # meson's system names don't quite map to our "traditional" names. In some
194 # places we need the "traditional" name, e.g., for mapping
195 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
196 # that purpose.
197 portname = host_system
199 if host_system == 'cygwin'
200   sema_kind = 'unnamed_posix'
201   cppflags += '-D_GNU_SOURCE'
202   dlsuffix = '.dll'
203   mod_link_args_fmt = ['@0@']
204   mod_link_with_name = 'lib@0@.a'
205   mod_link_with_dir = 'libdir'
207 elif host_system == 'darwin'
208   dlsuffix = '.dylib'
209   library_path_var = 'DYLD_LIBRARY_PATH'
211   export_file_format = 'darwin'
212   export_fmt = '-Wl,-exported_symbols_list,@0@'
214   mod_link_args_fmt = ['-bundle_loader', '@0@']
215   mod_link_with_dir = 'bindir'
216   mod_link_with_name = '@0@'
218   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
219   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
220   message('darwin sysroot: @0@'.format(pg_sysroot))
221   if pg_sysroot != ''
222     cflags += ['-isysroot', pg_sysroot]
223     ldflags += ['-isysroot', pg_sysroot]
224   endif
226   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
227   # don't want because a) it's different from what we do for autoconf, b) it
228   # causes warnings in macOS Ventura. But using -Wl,-undefined,error causes a
229   # warning starting in Sonoma. So only add -Wl,-undefined,error if it does
230   # not cause a warning.
231   if cc.has_multi_link_arguments('-Wl,-undefined,error', '-Werror')
232     ldflags_mod += '-Wl,-undefined,error'
233   endif
235   # Starting in Sonoma, the linker warns about the same library being
236   # linked twice.  Which can easily happen when multiple dependencies
237   # depend on the same library. Quiesce the ill considered warning.
238   ldflags += cc.get_supported_link_arguments('-Wl,-no_warn_duplicate_libraries')
240 elif host_system == 'freebsd'
241   sema_kind = 'unnamed_posix'
243 elif host_system == 'linux'
244   sema_kind = 'unnamed_posix'
245   cppflags += '-D_GNU_SOURCE'
247 elif host_system == 'netbsd'
248   # We must resolve all dynamic linking in the core server at program start.
249   # Otherwise the postmaster can self-deadlock due to signals interrupting
250   # resolution of calls, since NetBSD's linker takes a lock while doing that
251   # and some postmaster signal handlers do things that will also acquire that
252   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
253   # While there's not a hard reason to adopt these settings for our other
254   # executables, there's also little reason not to, so just add them to
255   # LDFLAGS.
256   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
258 elif host_system == 'openbsd'
259   # you're ok
261 elif host_system == 'sunos'
262   portname = 'solaris'
263   export_fmt = '-Wl,-M@0@'
264   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
266 elif host_system == 'windows'
267   portname = 'win32'
268   exesuffix = '.exe'
269   dlsuffix = '.dll'
270   library_path_var = ''
272   export_file_format = 'win'
273   export_file_suffix = 'def'
274   if cc.get_id() == 'msvc'
275     export_fmt = '/DEF:@0@'
276     mod_link_with_name = '@0@.lib'
277   else
278     export_fmt = '@0@'
279     mod_link_with_name = 'lib@0@.a'
280   endif
281   mod_link_args_fmt = ['@0@']
282   mod_link_with_dir = 'libdir'
284   shmem_kind = 'win32'
285   sema_kind = 'win32'
287   cdata.set('WIN32_STACK_RLIMIT', 4194304)
288   if cc.get_id() == 'msvc'
289     ldflags += '/INCREMENTAL:NO'
290     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
291     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
292   else
293     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
294     # Need to allow multiple definitions, we e.g. want to override getopt.
295     ldflags += '-Wl,--allow-multiple-definition'
296     # Ensure we get MSVC-like linking behavior.
297     ldflags += '-Wl,--disable-auto-import'
298   endif
300   os_deps += cc.find_library('ws2_32', required: true)
301   secur32_dep = cc.find_library('secur32', required: true)
302   backend_deps += secur32_dep
303   libpq_deps += secur32_dep
305   postgres_inc_d += 'src/include/port/win32'
306   if cc.get_id() == 'msvc'
307     postgres_inc_d += 'src/include/port/win32_msvc'
308   endif
310   windows = import('windows')
312 else
313   # XXX: Should we add an option to override the host_system as an escape
314   # hatch?
315   error('unknown host system: @0@'.format(host_system))
316 endif
320 ###############################################################
321 # Program paths
322 ###############################################################
324 # External programs
325 perl = find_program(get_option('PERL'), required: true, native: true)
326 python = find_program(get_option('PYTHON'), required: true, native: true)
327 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
328 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
329 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
330 prove = find_program(get_option('PROVE'), native: true, required: false)
331 tar = find_program(get_option('TAR'), native: true, required: false)
332 gzip = find_program(get_option('GZIP'), native: true, required: false)
333 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
334 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
335 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
336 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
337 missing = find_program('config/missing', native: true)
338 cp = find_program('cp', required: false, native: true)
339 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
340 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
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 if flex.found()
360   flex_version_c = run_command(flex, '--version', check: true)
361   flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
362 endif
363 flex_wrapper = files('src/tools/pgflex')
364 flex_cmd = [python, flex_wrapper,
365   '--builddir', '@BUILD_ROOT@',
366   '--srcdir', '@SOURCE_ROOT@',
367   '--privatedir', '@PRIVATE_DIR@',
368   '--flex', flex, '--perl', perl,
369   '-i', '@INPUT@', '-o', '@OUTPUT0@',
372 wget = find_program('wget', required: false, native: true)
373 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
375 install_files = files('src/tools/install_files')
379 ###############################################################
380 # Path to meson (for tests etc)
381 ###############################################################
383 # NB: this should really be part of meson, see
384 # https://github.com/mesonbuild/meson/issues/8511
385 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
387 if meson_binpath_r.stdout() == ''
388   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
389     meson_binpath_r.returncode(),
390     meson_binpath_r.stdout(),
391     meson_binpath_r.stderr()))
392 endif
394 meson_binpath_s = meson_binpath_r.stdout().split('\n')
395 meson_binpath_len = meson_binpath_s.length()
397 if meson_binpath_len < 1
398   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
399 endif
401 i = 0
402 meson_impl = ''
403 meson_binpath = ''
404 meson_args = []
405 foreach e : meson_binpath_s
406   if i == 0
407     meson_impl = e
408   elif i == 1
409     meson_binpath = e
410   else
411     meson_args += e
412   endif
413   i += 1
414 endforeach
416 if meson_impl not in ['muon', 'meson']
417   error('unknown meson implementation "@0@"'.format(meson_impl))
418 endif
420 meson_bin = find_program(meson_binpath, native: true)
424 ###############################################################
425 # Option Handling
426 ###############################################################
428 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
429 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
431 blocksize = get_option('blocksize').to_int() * 1024
433 if get_option('segsize_blocks') != 0
434   if get_option('segsize') != 1
435     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
436   endif
438   segsize = get_option('segsize_blocks')
439 else
440   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
441 endif
443 cdata.set('BLCKSZ', blocksize, description:
444 '''Size of a disk block --- this also limits the size of a tuple. You can set
445    it bigger if you need bigger tuples (although TOAST should reduce the need
446    to have large tuples, since fields can be spread across multiple tuples).
447    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
448    currently 2^15 (32768). This is determined by the 15-bit widths of the
449    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
450    Changing BLCKSZ requires an initdb.''')
452 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
453 cdata.set('RELSEG_SIZE', segsize)
454 cdata.set('DEF_PGPORT', get_option('pgport'))
455 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
456 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
457 if get_option('system_tzdata') != ''
458   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
459 endif
463 ###############################################################
464 # Directories
465 ###############################################################
467 # These are set by the equivalent --xxxdir configure options.  We
468 # append "postgresql" to some of them, if the string does not already
469 # contain "pgsql" or "postgres", in order to avoid directory clutter.
471 pkg = 'postgresql'
473 dir_prefix = get_option('prefix')
475 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
477 dir_bin = get_option('bindir')
479 dir_data = get_option('datadir')
480 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
481   dir_data = dir_data / pkg
482 endif
484 dir_sysconf = get_option('sysconfdir')
485 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
486   dir_sysconf = dir_sysconf / pkg
487 endif
489 dir_lib = get_option('libdir')
491 dir_lib_pkg = dir_lib
492 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
493   dir_lib_pkg = dir_lib_pkg / pkg
494 endif
496 dir_pgxs = dir_lib_pkg / 'pgxs'
498 dir_include = get_option('includedir')
500 dir_include_pkg = dir_include
501 dir_include_pkg_rel = ''
502 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
503   dir_include_pkg = dir_include_pkg / pkg
504   dir_include_pkg_rel = pkg
505 endif
507 dir_man = get_option('mandir')
509 # FIXME: These used to be separately configurable - worth adding?
510 dir_doc = get_option('datadir') / 'doc'
511 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
512   dir_doc = dir_doc / pkg
513 endif
514 dir_doc_html = dir_doc / 'html'
516 dir_locale = get_option('localedir')
519 # Derived values
520 dir_bitcode = dir_lib_pkg / 'bitcode'
521 dir_include_internal = dir_include_pkg / 'internal'
522 dir_include_server = dir_include_pkg / 'server'
523 dir_include_extension = dir_include_server / 'extension'
524 dir_data_extension = dir_data / 'extension'
525 dir_doc_extension = dir_doc / 'extension'
529 ###############################################################
530 # Search paths, preparation for compiler tests
532 # NB: Arguments added later are not automatically used for subsequent
533 # configuration-time checks (so they are more isolated). If they should be
534 # used, they need to be added to test_c_args as well.
535 ###############################################################
537 postgres_inc = [include_directories(postgres_inc_d)]
538 test_lib_d = postgres_lib_d
539 test_c_args = cppflags + cflags
543 ###############################################################
544 # Library: bsd-auth
545 ###############################################################
547 bsd_authopt = get_option('bsd_auth')
548 bsd_auth = not_found_dep
549 if cc.check_header('bsd_auth.h', required: bsd_authopt,
550     args: test_c_args, include_directories: postgres_inc)
551   cdata.set('USE_BSD_AUTH', 1)
552   bsd_auth = declare_dependency()
553 endif
557 ###############################################################
558 # Library: bonjour
560 # For now don't search for DNSServiceRegister in a library - only Apple's
561 # Bonjour implementation, which is always linked, works.
562 ###############################################################
564 bonjouropt = get_option('bonjour')
565 bonjour = not_found_dep
566 if cc.check_header('dns_sd.h', required: bonjouropt,
567     args: test_c_args, include_directories: postgres_inc) and \
568    cc.has_function('DNSServiceRegister',
569     args: test_c_args, include_directories: postgres_inc)
570   cdata.set('USE_BONJOUR', 1)
571   bonjour = declare_dependency()
572 endif
576 ###############################################################
577 # Option: docs in HTML and man page format
578 ###############################################################
580 docs_opt = get_option('docs')
581 docs_dep = not_found_dep
582 if not docs_opt.disabled()
583   if xmllint_bin.found() and xsltproc_bin.found()
584     docs_dep = declare_dependency()
585   elif docs_opt.enabled()
586     error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
587   endif
588 endif
592 ###############################################################
593 # Option: docs in PDF format
594 ###############################################################
596 docs_pdf_opt = get_option('docs_pdf')
597 docs_pdf_dep = not_found_dep
598 if not docs_pdf_opt.disabled()
599   fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
600   if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
601     docs_pdf_dep = declare_dependency()
602   elif docs_pdf_opt.enabled()
603     error('missing required tools for docs in PDF format')
604   endif
605 endif
609 ###############################################################
610 # Library: GSSAPI
611 ###############################################################
613 gssapiopt = get_option('gssapi')
614 krb_srvtab = ''
615 have_gssapi = false
616 if not gssapiopt.disabled()
617   gssapi = dependency('krb5-gssapi', required: gssapiopt)
618   have_gssapi = gssapi.found()
620   if not have_gssapi
621   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
622       args: test_c_args, include_directories: postgres_inc)
623     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
624   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
625     cdata.set('HAVE_GSSAPI_H', 1)
626   else
627     have_gssapi = false
628   endif
630   if not have_gssapi
631   elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi, required: false,
632       args: test_c_args, include_directories: postgres_inc)
633     cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
634   elif cc.check_header('gssapi_ext.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
635     cdata.set('HAVE_GSSAPI_EXT_H', 1)
636   else
637     have_gssapi = false
638   endif
640   if not have_gssapi
641   elif cc.has_function('gss_store_cred_into', dependencies: gssapi,
642       args: test_c_args, include_directories: postgres_inc)
643     cdata.set('ENABLE_GSS', 1)
645     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
646     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
647   elif gssapiopt.enabled()
648     error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
649   else
650     have_gssapi = false
651   endif
652 endif
653 if not have_gssapi
654   gssapi = not_found_dep
655 endif
659 ###############################################################
660 # Library: ldap
661 ###############################################################
663 ldapopt = get_option('ldap')
664 if ldapopt.disabled()
665   ldap = not_found_dep
666   ldap_r = not_found_dep
667 elif host_system == 'windows'
668   ldap = cc.find_library('wldap32', required: ldapopt)
669   ldap_r = ldap
670 else
671   # macos framework dependency is buggy for ldap (one can argue whether it's
672   # Apple's or meson's fault), leading to an endless recursion with ldap.h
673   # including itself. See https://github.com/mesonbuild/meson/issues/10002
674   # Luckily we only need pkg-config support, so the workaround isn't
675   # complicated.
676   ldap = dependency('ldap', method: 'pkg-config', required: false)
677   ldap_r = ldap
679   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
680   # installed
681   if not ldap.found()
682     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
683       has_headers: 'ldap.h', header_include_directories: postgres_inc)
685     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
686     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
687     # library from a separate OpenLDAP installation).  The most reliable
688     # way to check that is to check for a function introduced in 2.5.
689     if not ldap.found()
690       # don't have ldap, we shouldn't check for ldap_r
691     elif cc.has_function('ldap_verify_credentials',
692         dependencies: ldap, args: test_c_args)
693       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
694     else
696       # Use ldap_r for FE if available, else assume ldap is thread-safe.
697       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
698         has_headers: 'ldap.h', header_include_directories: postgres_inc)
699       if not ldap_r.found()
700         ldap_r = ldap
701       else
702         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
703         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
704       endif
706       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
707       # process.  Check for OpenLDAP versions known not to tolerate doing so;
708       # assume non-OpenLDAP implementations are safe.  The dblink test suite
709       # exercises the hazardous interaction directly.
710       compat_test_code = '''
711 #include <ldap.h>
712 #if !defined(LDAP_VENDOR_VERSION) || \
713      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
714       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
715 choke me
716 #endif
718       if not cc.compiles(compat_test_code,
719           name: 'LDAP implementation compatible',
720           dependencies: ldap, args: test_c_args)
721         warning('''
722 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
723 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
724 *** also uses LDAP will crash on exit.''')
725       endif
726     endif
727   endif
729   if ldap.found() and cc.has_function('ldap_initialize',
730       dependencies: ldap, args: test_c_args)
731     cdata.set('HAVE_LDAP_INITIALIZE', 1)
732   endif
733 endif
735 if ldap.found()
736   assert(ldap_r.found())
737   cdata.set('USE_LDAP', 1)
738 else
739   assert(not ldap_r.found())
740 endif
744 ###############################################################
745 # Library: LLVM
746 ###############################################################
748 llvmopt = get_option('llvm')
749 llvm = not_found_dep
750 if add_languages('cpp', required: llvmopt, native: false)
751   llvm = dependency('llvm', version: '>=10', method: 'config-tool', required: llvmopt)
753   if llvm.found()
755     cdata.set('USE_LLVM', 1)
757     cpp = meson.get_compiler('cpp')
759     llvm_binpath = llvm.get_variable(configtool: 'bindir')
761     ccache = find_program('ccache', native: true, required: false)
762     clang = find_program(llvm_binpath / 'clang', required: true)
763   endif
764 elif llvmopt.auto()
765   message('llvm requires a C++ compiler')
766 endif
770 ###############################################################
771 # Library: icu
772 ###############################################################
774 icuopt = get_option('icu')
775 if not icuopt.disabled()
776   icu = dependency('icu-uc', required: icuopt)
777   icu_i18n = dependency('icu-i18n', required: icuopt)
779   if icu.found()
780     cdata.set('USE_ICU', 1)
781   endif
783 else
784   icu = not_found_dep
785   icu_i18n = not_found_dep
786 endif
790 ###############################################################
791 # Library: libxml
792 ###############################################################
794 libxmlopt = get_option('libxml')
795 if not libxmlopt.disabled()
796   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
798   if libxml.found()
799     cdata.set('USE_LIBXML', 1)
800   endif
801 else
802   libxml = not_found_dep
803 endif
807 ###############################################################
808 # Library: libxslt
809 ###############################################################
811 libxsltopt = get_option('libxslt')
812 if not libxsltopt.disabled()
813   libxslt = dependency('libxslt', required: libxsltopt)
815   if libxslt.found()
816     cdata.set('USE_LIBXSLT', 1)
817   endif
818 else
819   libxslt = not_found_dep
820 endif
824 ###############################################################
825 # Library: lz4
826 ###############################################################
828 lz4opt = get_option('lz4')
829 if not lz4opt.disabled()
830   lz4 = dependency('liblz4', required: lz4opt)
832   if lz4.found()
833     cdata.set('USE_LZ4', 1)
834     cdata.set('HAVE_LIBLZ4', 1)
835   endif
837 else
838   lz4 = not_found_dep
839 endif
843 ###############################################################
844 # Library: Tcl (for pltcl)
846 # NB: tclConfig.sh is used in autoconf build for getting
847 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
848 # variables. For now we have not seen a need to copy
849 # that behaviour to the meson build.
850 ###############################################################
852 tclopt = get_option('pltcl')
853 tcl_version = get_option('tcl_version')
854 tcl_dep = not_found_dep
855 if not tclopt.disabled()
857   # via pkg-config
858   tcl_dep = dependency(tcl_version, required: false)
860   if not tcl_dep.found()
861     tcl_dep = cc.find_library(tcl_version,
862       required: tclopt,
863       dirs: test_lib_d)
864   endif
866   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
867     tcl_dep = not_found_dep
868   endif
869 endif
873 ###############################################################
874 # Library: pam
875 ###############################################################
877 pamopt = get_option('pam')
878 if not pamopt.disabled()
879   pam = dependency('pam', required: false)
881   if not pam.found()
882     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
883   endif
885   if pam.found()
886     pam_header_found = false
888     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
889     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
890         args: test_c_args, include_directories: postgres_inc)
891       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
892       pam_header_found = true
893     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
894         args: test_c_args, include_directories: postgres_inc)
895       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
896       pam_header_found = true
897     endif
899     if pam_header_found
900       cdata.set('USE_PAM', 1)
901     else
902       pam = not_found_dep
903     endif
904   endif
905 else
906   pam = not_found_dep
907 endif
911 ###############################################################
912 # Library: Perl (for plperl)
913 ###############################################################
915 perlopt = get_option('plperl')
916 perl_dep = not_found_dep
917 if not perlopt.disabled()
918   perl_may_work = true
920   # First verify that perl has the necessary dependencies installed
921   perl_mods = run_command(
922     [perl,
923      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
924      '-e', ''],
925     check: false)
926   if perl_mods.returncode() != 0
927     perl_may_work = false
928     perl_msg = 'perl installation does not have the required modules'
929   endif
931   # Then inquire perl about its configuration
932   if perl_may_work
933     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
934     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
935     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
936     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
937     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
939     perl_inc_dir = '@0@/CORE'.format(archlibexp)
941     if perlversion.version_compare('< 5.14')
942       perl_may_work = false
943       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
944     elif useshrplib != 'true'
945       perl_may_work = false
946       perl_msg = 'need a shared perl'
947     endif
948   endif
950   if perl_may_work
951     # On most platforms, archlibexp is also where the Perl include files live ...
952     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
953     # ... but on newer macOS versions, we must use -iwithsysroot to look
954     # under sysroot
955     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
956        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
957       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
958     endif
960     # check compiler finds header
961     if not cc.has_header('perl.h', required: false,
962         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
963       perl_may_work = false
964       perl_msg = 'missing perl.h'
965     endif
966   endif
968   if perl_may_work
969     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
971     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
972     foreach flag : perl_ccflags_r.split(' ')
973       if flag.startswith('-D') and \
974           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
975         perl_ccflags += flag
976       endif
977     endforeach
979     if host_system == 'windows'
980       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
982       if cc.get_id() == 'msvc'
983         # prevent binary mismatch between MSVC built plperl and Strawberry or
984         # msys ucrt perl libraries
985         perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
986       endif
987     endif
989     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
990     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
992     # We are after Embed's ldopts, but without the subset mentioned in
993     # Config's ccdlflags and ldflags.  (Those are the choices of those who
994     # built the Perl installation, which are not necessarily appropriate
995     # for building PostgreSQL.)
996     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
997     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
998     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
1000     perl_ldopts = []
1001     foreach ldopt : ldopts.split(' ')
1002       if ldopt == '' or ldopt in undesired
1003         continue
1004       endif
1006       perl_ldopts += ldopt.strip('"')
1007     endforeach
1009     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
1010     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1012     perl_dep_int = declare_dependency(
1013       compile_args: perl_ccflags,
1014       link_args: perl_ldopts,
1015       version: perlversion,
1016     )
1018     # While we're at it, check that we can link to libperl.
1019     # On most platforms, if perl.h is there then libperl.so will be too, but
1020     # at this writing Debian packages them separately.
1021     perl_link_test = '''
1022 /* see plperl.h */
1023 #ifdef _MSC_VER
1024 #define __inline__ inline
1025 #endif
1026 #include <EXTERN.h>
1027 #include <perl.h>
1028 int main(void)
1030 perl_alloc();
1031 }'''
1032     if not cc.links(perl_link_test, name: 'libperl',
1033           args: test_c_args + perl_ccflags + perl_ldopts,
1034           include_directories: postgres_inc)
1035       perl_may_work = false
1036       perl_msg = 'missing libperl'
1037     endif
1039   endif # perl_may_work
1041   if perl_may_work
1042     perl_dep = perl_dep_int
1043   else
1044     if perlopt.enabled()
1045       error('dependency plperl failed: @0@'.format(perl_msg))
1046     else
1047       message('disabling optional dependency plperl: @0@'.format(perl_msg))
1048     endif
1049   endif
1050 endif
1054 ###############################################################
1055 # Library: Python (for plpython)
1056 ###############################################################
1058 pyopt = get_option('plpython')
1059 python3_dep = not_found_dep
1060 if not pyopt.disabled()
1061   pm = import('python')
1062   python3_inst = pm.find_installation(python.path(), required: pyopt)
1063   if python3_inst.found()
1064     python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1065     # Remove this check after we depend on Meson >= 1.1.0
1066     if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1067       python3_dep = not_found_dep
1068     endif
1069   endif
1070 endif
1074 ###############################################################
1075 # Library: Readline
1076 ###############################################################
1078 if not get_option('readline').disabled()
1079   libedit_preferred = get_option('libedit_preferred')
1080   # Set the order of readline dependencies
1081   check_readline_deps = libedit_preferred ? \
1082     ['libedit', 'readline'] : ['readline', 'libedit']
1084   foreach readline_dep : check_readline_deps
1085     readline = dependency(readline_dep, required: false)
1086     if not readline.found()
1087       readline = cc.find_library(readline_dep,
1088         required: get_option('readline'),
1089         dirs: test_lib_d)
1090     endif
1091     if readline.found()
1092       break
1093     endif
1094   endforeach
1096   if readline.found()
1097     cdata.set('HAVE_LIBREADLINE', 1)
1099     editline_prefix = {
1100       'header_prefix': 'editline/',
1101       'flag_prefix': 'EDITLINE_',
1102     }
1103     readline_prefix = {
1104       'header_prefix': 'readline/',
1105       'flag_prefix': 'READLINE_',
1106     }
1107     default_prefix = {
1108       'header_prefix': '',
1109       'flag_prefix': '',
1110     }
1112     # Set the order of prefixes
1113     prefixes = libedit_preferred ? \
1114       [editline_prefix, default_prefix, readline_prefix] : \
1115       [readline_prefix, default_prefix, editline_prefix]
1117     at_least_one_header_found = false
1118     foreach header : ['history', 'readline']
1119       is_found = false
1120       foreach prefix : prefixes
1121         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1122         # Check history.h and readline.h
1123         if not is_found and cc.has_header(header_file,
1124             args: test_c_args, include_directories: postgres_inc,
1125             dependencies: [readline], required: false)
1126           if header == 'readline'
1127             readline_h = header_file
1128           endif
1129           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1130           is_found = true
1131           at_least_one_header_found = true
1132         endif
1133       endforeach
1134     endforeach
1136     if not at_least_one_header_found
1137       error('''readline header not found
1138 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1139 failure. It is possible the compiler isn't looking in the proper directory.
1140 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1141     endif
1143     check_funcs = [
1144       'append_history',
1145       'history_truncate_file',
1146       'rl_completion_matches',
1147       'rl_filename_completion_function',
1148       'rl_reset_screen_size',
1149       'rl_variable_bind',
1150     ]
1152     foreach func : check_funcs
1153       found = cc.has_function(func, dependencies: [readline],
1154         args: test_c_args, include_directories: postgres_inc)
1155       cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1156     endforeach
1158     check_vars = [
1159       'rl_completion_suppress_quote',
1160       'rl_filename_quote_characters',
1161       'rl_filename_quoting_function',
1162     ]
1164     foreach var : check_vars
1165       cdata.set('HAVE_' + var.to_upper(),
1166         cc.has_header_symbol(readline_h, var,
1167           args: test_c_args, include_directories: postgres_inc,
1168           prefix: '#include <stdio.h>',
1169           dependencies: [readline]) ? 1 : false)
1170     endforeach
1172     # If found via cc.find_library() ensure headers are found when using the
1173     # dependency. On meson < 0.57 one cannot do compiler checks using the
1174     # dependency returned by declare_dependency(), so we can't do this above.
1175     if readline.type_name() == 'library'
1176       readline = declare_dependency(dependencies: readline,
1177         include_directories: postgres_inc)
1178     endif
1180     # On windows with mingw readline requires auto-import to successfully
1181     # link, as the headers don't use declspec(dllimport)
1182     if host_system == 'windows' and cc.get_id() != 'msvc'
1183       readline = declare_dependency(dependencies: readline,
1184         link_args: '-Wl,--enable-auto-import')
1185     endif
1186   endif
1188   # XXX: Figure out whether to implement mingw warning equivalent
1189 else
1190   readline = not_found_dep
1191 endif
1195 ###############################################################
1196 # Library: selinux
1197 ###############################################################
1199 selinux = not_found_dep
1200 selinuxopt = get_option('selinux')
1201 if meson.version().version_compare('>=0.59')
1202   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1203 endif
1204 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1205 cdata.set('HAVE_LIBSELINUX',
1206   selinux.found() ? 1 : false)
1210 ###############################################################
1211 # Library: systemd
1212 ###############################################################
1214 systemd = not_found_dep
1215 systemdopt = get_option('systemd')
1216 if meson.version().version_compare('>=0.59')
1217   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1218 endif
1219 systemd = dependency('libsystemd', required: systemdopt)
1220 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1224 ###############################################################
1225 # Library: SSL
1226 ###############################################################
1228 ssl = not_found_dep
1229 ssl_library = 'none'
1230 sslopt = get_option('ssl')
1232 if sslopt == 'auto' and auto_features.disabled()
1233   sslopt = 'none'
1234 endif
1236 if sslopt in ['auto', 'openssl']
1237   openssl_required = (sslopt == 'openssl')
1239   # Try to find openssl via pkg-config et al, if that doesn't work
1240   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1241   # the library names that we know about.
1243   # via pkg-config et al
1244   ssl = dependency('openssl', required: false)
1245   # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1246   # we pass cc.find_library() results if necessary
1247   ssl_int = []
1249   # via library + headers
1250   if not ssl.found()
1251     ssl_lib = cc.find_library('ssl',
1252       dirs: test_lib_d,
1253       header_include_directories: postgres_inc,
1254       has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1255       required: openssl_required)
1256     crypto_lib = cc.find_library('crypto',
1257       dirs: test_lib_d,
1258       required: openssl_required)
1259     if ssl_lib.found() and crypto_lib.found()
1260       ssl_int = [ssl_lib, crypto_lib]
1261       ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1262     endif
1263   elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1264        cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1265     ssl_int = [ssl]
1266   else
1267     ssl = not_found_dep
1268   endif
1270   if ssl.found()
1271     check_funcs = [
1272       ['CRYPTO_new_ex_data', {'required': true}],
1273       ['SSL_new', {'required': true}],
1275       # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1276       ['SSL_CTX_set_cert_cb'],
1278       # Functions introduced in OpenSSL 1.1.0. We used to check for
1279       # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1280       # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1281       # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1282       # functions.
1283       ['OPENSSL_init_ssl'],
1284       ['BIO_meth_new'],
1285       ['ASN1_STRING_get0_data'],
1286       ['HMAC_CTX_new'],
1287       ['HMAC_CTX_free'],
1289       # OpenSSL versions before 1.1.0 required setting callback functions, for
1290       # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1291       # function was removed.
1292       ['CRYPTO_lock'],
1294       # Function introduced in OpenSSL 1.1.1
1295       ['X509_get_signature_info'],
1296     ]
1298     are_openssl_funcs_complete = true
1299     foreach c : check_funcs
1300       func = c.get(0)
1301       val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1302       required = c.get(1, {}).get('required', false)
1303       if required and not val
1304         are_openssl_funcs_complete = false
1305         if openssl_required
1306           error('openssl function @0@ is required'.format(func))
1307         endif
1308         break
1309       elif not required
1310         cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1311       endif
1312     endforeach
1314     if are_openssl_funcs_complete
1315       cdata.set('USE_OPENSSL', 1,
1316                 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1317       cdata.set('OPENSSL_API_COMPAT', '0x10002000L',
1318                 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1319       ssl_library = 'openssl'
1320     else
1321       ssl = not_found_dep
1322     endif
1323   endif
1324 endif
1326 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1327   error('no SSL library found')
1328 endif
1332 ###############################################################
1333 # Library: uuid
1334 ###############################################################
1336 uuidopt = get_option('uuid')
1337 if uuidopt != 'none'
1338   uuidname = uuidopt.to_upper()
1339   if uuidopt == 'e2fs'
1340     uuid = dependency('uuid', required: true)
1341     uuidfunc = 'uuid_generate'
1342     uuidheader = 'uuid/uuid.h'
1343   elif uuidopt == 'bsd'
1344     # libc should have uuid function
1345     uuid = declare_dependency()
1346     uuidfunc = 'uuid_to_string'
1347     uuidheader = 'uuid.h'
1348   elif uuidopt == 'ossp'
1349     uuid = dependency('ossp-uuid', required: true)
1350     uuidfunc = 'uuid_export'
1351     uuidheader = 'uuid.h'
1352   else
1353     error('unknown uuid build option value: @0@'.format(uuidopt))
1354   endif
1356   if not cc.has_header_symbol(uuidheader, uuidfunc,
1357                               args: test_c_args,
1358                               include_directories: postgres_inc,
1359                               dependencies: uuid)
1360     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1361   endif
1362   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1364   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1365            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1366 else
1367   uuid = not_found_dep
1368 endif
1372 ###############################################################
1373 # Library: zlib
1374 ###############################################################
1376 zlibopt = get_option('zlib')
1377 zlib = not_found_dep
1378 if not zlibopt.disabled()
1379   zlib_t = dependency('zlib', required: zlibopt)
1381   if zlib_t.type_name() == 'internal'
1382     # if fallback was used, we don't need to test if headers are present (they
1383     # aren't built yet, so we can't test)
1384     zlib = zlib_t
1385   elif not zlib_t.found()
1386     warning('did not find zlib')
1387   elif not cc.has_header('zlib.h',
1388       args: test_c_args, include_directories: postgres_inc,
1389       dependencies: [zlib_t], required: zlibopt)
1390     warning('zlib header not found')
1391   else
1392     zlib = zlib_t
1393   endif
1395   if zlib.found()
1396     cdata.set('HAVE_LIBZ', 1)
1397   endif
1398 endif
1402 ###############################################################
1403 # Library: tap test dependencies
1404 ###############################################################
1406 # Check whether tap tests are enabled or not
1407 tap_tests_enabled = false
1408 tapopt = get_option('tap_tests')
1409 if not tapopt.disabled()
1410   # Checking for perl modules for tap tests
1411   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1412   if perl_ipc_run_check.returncode() != 0
1413     message(perl_ipc_run_check.stderr().strip())
1414     if tapopt.enabled()
1415       error('Additional Perl modules are required to run TAP tests.')
1416     else
1417       warning('Additional Perl modules are required to run TAP tests.')
1418     endif
1419   else
1420     tap_tests_enabled = true
1421   endif
1422 endif
1426 ###############################################################
1427 # Library: zstd
1428 ###############################################################
1430 zstdopt = get_option('zstd')
1431 if not zstdopt.disabled()
1432   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1434   if zstd.found()
1435     cdata.set('USE_ZSTD', 1)
1436     cdata.set('HAVE_LIBZSTD', 1)
1437   endif
1439 else
1440   zstd = not_found_dep
1441 endif
1445 ###############################################################
1446 # Compiler tests
1447 ###############################################################
1449 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1450 # unnecessarily, because we optionally rely on newer features.
1451 c99_test = '''
1452 #include <stdbool.h>
1453 #include <complex.h>
1454 #include <tgmath.h>
1455 #include <inttypes.h>
1457 struct named_init_test {
1458   int a;
1459   int b;
1462 extern void structfunc(struct named_init_test);
1464 int main(int argc, char **argv)
1466   struct named_init_test nit = {
1467     .a = 3,
1468     .b = 5,
1469   };
1471   for (int loop_var = 0; loop_var < 3; loop_var++)
1472   {
1473     nit.a += nit.b;
1474   }
1476   structfunc((struct named_init_test){1, 0});
1478   return nit.a != 0;
1482 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1483   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1484         args: test_c_args + ['-std=c99'])
1485     test_c_args += '-std=c99'
1486     cflags += '-std=c99'
1487   else
1488     error('C compiler does not support C99')
1489   endif
1490 endif
1492 sizeof_long = cc.sizeof('long', args: test_c_args)
1493 cdata.set('SIZEOF_LONG', sizeof_long)
1494 if sizeof_long == 8
1495   cdata.set('HAVE_LONG_INT_64', 1)
1496   pg_int64_type = 'long int'
1497   cdata.set_quoted('INT64_MODIFIER', 'l')
1498 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1499   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1500   pg_int64_type = 'long long int'
1501   cdata.set_quoted('INT64_MODIFIER', 'll')
1502 else
1503   error('do not know how to get a 64bit int')
1504 endif
1505 cdata.set('PG_INT64_TYPE', pg_int64_type)
1507 if host_machine.endian() == 'big'
1508   cdata.set('WORDS_BIGENDIAN', 1)
1509 endif
1511 # Determine memory alignment requirements for the basic C data types.
1513 alignof_types = ['short', 'int', 'long', 'double']
1514 foreach t : alignof_types
1515   align = cc.alignment(t, args: test_c_args)
1516   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1517 endforeach
1519 # Compute maximum alignment of any basic type.
1521 # We require 'double' to have the strictest alignment among the basic types,
1522 # because otherwise the C ABI might impose 8-byte alignment on some of the
1523 # other C types that correspond to TYPALIGN_DOUBLE SQL types.  That could
1524 # cause a mismatch between the tuple layout and the C struct layout of a
1525 # catalog tuple.  We used to carefully order catalog columns such that any
1526 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1527 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1528 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1530 # We assume without checking that int64's alignment is at least as strong
1531 # as long, char, short, or int.  Note that we intentionally do not consider
1532 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1533 # would be too much of a penalty for disk and memory space.
1534 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1535 if cc.alignment(pg_int64_type, args: test_c_args) > alignof_double
1536   error('alignment of int64 is greater than the alignment of double')
1537 endif
1538 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1540 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1541 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1544 # Check if __int128 is a working 128 bit integer type, and if so
1545 # define PG_INT128_TYPE to that typename.
1547 # This currently only detects a GCC/clang extension, but support for other
1548 # environments may be added in the future.
1550 # For the moment we only test for support for 128bit math; support for
1551 # 128bit literals and snprintf is not required.
1552 if cc.links('''
1553   /*
1554    * We don't actually run this test, just link it to verify that any support
1555    * functions needed for __int128 are present.
1556    *
1557    * These are globals to discourage the compiler from folding all the
1558    * arithmetic tests down to compile-time constants.  We do not have
1559    * convenient support for 128bit literals at this point...
1560    */
1561   __int128 a = 48828125;
1562   __int128 b = 97656250;
1564   int main(void)
1565   {
1566       __int128 c,d;
1567       a = (a << 12) + 1; /* 200000000001 */
1568       b = (b << 12) + 5; /* 400000000005 */
1569       /* try the most relevant arithmetic ops */
1570       c = a * b;
1571       d = (c + b) / b;
1572       /* must use the results, else compiler may optimize arithmetic away */
1573       return d != a+1;
1574   }''',
1575   name: '__int128',
1576   args: test_c_args)
1578   buggy_int128 = false
1580   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1581   # If not cross-compiling, we can test for bugs and disable use of __int128
1582   # with buggy compilers.  If cross-compiling, hope for the best.
1583   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1584   if not meson.is_cross_build()
1585     r = cc.run('''
1586     /* This must match the corresponding code in c.h: */
1587     #if defined(__GNUC__) || defined(__SUNPRO_C)
1588     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1589     #elif defined(_MSC_VER)
1590     #define pg_attribute_aligned(a) __declspec(align(a))
1591     #endif
1592     typedef __int128 int128a
1593     #if defined(pg_attribute_aligned)
1594     pg_attribute_aligned(8)
1595     #endif
1596     ;
1598     int128a holder;
1599     void pass_by_val(void *buffer, int128a par) { holder = par; }
1601     int main(void)
1602     {
1603         long int i64 = 97656225L << 12;
1604         int128a q;
1605         pass_by_val(main, (int128a) i64);
1606         q = (int128a) i64;
1607         return q != holder;
1608     }''',
1609     name: '__int128 alignment bug',
1610     args: test_c_args)
1611     assert(r.compiled())
1612     if r.returncode() != 0
1613       buggy_int128 = true
1614       message('__int128 support present but buggy and thus disabled')
1615     endif
1616   endif
1618   if not buggy_int128
1619     cdata.set('PG_INT128_TYPE', '__int128')
1620     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1621   endif
1622 endif
1625 # Check if the C compiler knows computed gotos (gcc extension, also
1626 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1628 # Checking whether computed gotos are supported syntax-wise ought to
1629 # be enough, as the syntax is otherwise illegal.
1630 if cc.compiles('''
1631     static inline int foo(void)
1632     {
1633       void *labeladdrs[] = {&&my_label};
1634       goto *labeladdrs[0];
1635       my_label:
1636       return 1;
1637     }''',
1638     args: test_c_args)
1639   cdata.set('HAVE_COMPUTED_GOTO', 1)
1640 endif
1643 # Check if the C compiler understands _Static_assert(),
1644 # and define HAVE__STATIC_ASSERT if so.
1646 # We actually check the syntax ({ _Static_assert(...) }), because we need
1647 # gcc-style compound expressions to be able to wrap the thing into macros.
1648 if cc.compiles('''
1649     int main(int arg, char **argv)
1650     {
1651         ({ _Static_assert(1, "foo"); });
1652     }
1653     ''',
1654     args: test_c_args)
1655   cdata.set('HAVE__STATIC_ASSERT', 1)
1656 endif
1659 # We use <stdbool.h> if we have it and it declares type bool as having
1660 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1661 if cc.has_type('_Bool', args: test_c_args) \
1662     and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1663     and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1664   cdata.set('HAVE__BOOL', 1)
1665   cdata.set('PG_USE_STDBOOL', 1)
1666 endif
1669 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1670 # warning for each use of %m.
1671 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1672 testsrc = '''
1673 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1674 static void call_log(void)
1676     emit_log(0, "error: %s: %m", "foo");
1679 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1680 foreach a : printf_attributes
1681   if cc.compiles(testsrc.format(a),
1682       args: test_c_args + attrib_error_args, name: 'format ' + a)
1683     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1684     break
1685   endif
1686 endforeach
1689 if cc.has_function_attribute('visibility:default') and \
1690     cc.has_function_attribute('visibility:hidden')
1691   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1693   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1694   # inlineshidden to C code as well... And either way, we want to put these
1695   # flags into exported files (pgxs, .pc files).
1696   cflags_mod += '-fvisibility=hidden'
1697   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1698   ldflags_mod += '-fvisibility=hidden'
1699 endif
1702 # Check if various builtins exist. Some builtins are tested separately,
1703 # because we want to test something more complicated than the generic case.
1704 builtins = [
1705   'bswap16',
1706   'bswap32',
1707   'bswap64',
1708   'clz',
1709   'ctz',
1710   'constant_p',
1711   'frame_address',
1712   'popcount',
1713   'unreachable',
1716 foreach builtin : builtins
1717   fname = '__builtin_@0@'.format(builtin)
1718   if cc.has_function(fname, args: test_c_args)
1719     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1720   endif
1721 endforeach
1724 # Check if the C compiler understands __builtin_types_compatible_p,
1725 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1727 # We check usage with __typeof__, though it's unlikely any compiler would
1728 # have the former and not the latter.
1729 if cc.compiles('''
1730     static int x;
1731     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1732     ''',
1733     name: '__builtin_types_compatible_p',
1734     args: test_c_args)
1735   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1736 endif
1739 # Check if the C compiler understands __builtin_$op_overflow(),
1740 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1742 # Check for the most complicated case, 64 bit multiplication, as a
1743 # proxy for all of the operations.  To detect the case where the compiler
1744 # knows the function but library support is missing, we must link not just
1745 # compile, and store the results in global variables so the compiler doesn't
1746 # optimize away the call.
1747 if cc.links('''
1748     INT64 a = 1;
1749     INT64 b = 1;
1750     INT64 result;
1752     int main(void)
1753     {
1754         return __builtin_mul_overflow(a, b, &result);
1755     }''',
1756     name: '__builtin_mul_overflow',
1757     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1758     )
1759   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1760 endif
1763 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1764 # here. To prevent problems due to two detection methods working, stop
1765 # checking after one.
1766 if cc.links('''
1767     #include <cpuid.h>
1768     int main(int arg, char **argv)
1769     {
1770         unsigned int exx[4] = {0, 0, 0, 0};
1771         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1772     }
1773     ''', name: '__get_cpuid',
1774     args: test_c_args)
1775   cdata.set('HAVE__GET_CPUID', 1)
1776 elif cc.links('''
1777     #include <intrin.h>
1778     int main(int arg, char **argv)
1779     {
1780         unsigned int exx[4] = {0, 0, 0, 0};
1781         __cpuid(exx, 1);
1782     }
1783     ''', name: '__cpuid',
1784     args: test_c_args)
1785   cdata.set('HAVE__CPUID', 1)
1786 endif
1789 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1790 if cc.links('''
1791     #include <cpuid.h>
1792     int main(int arg, char **argv)
1793     {
1794         unsigned int exx[4] = {0, 0, 0, 0};
1795         __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1796     }
1797     ''', name: '__get_cpuid_count',
1798     args: test_c_args)
1799   cdata.set('HAVE__GET_CPUID_COUNT', 1)
1800 elif cc.links('''
1801     #include <intrin.h>
1802     int main(int arg, char **argv)
1803     {
1804         unsigned int exx[4] = {0, 0, 0, 0};
1805         __cpuidex(exx, 7, 0);
1806     }
1807     ''', name: '__cpuidex',
1808     args: test_c_args)
1809   cdata.set('HAVE__CPUIDEX', 1)
1810 endif
1813 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1814 # versions of clang do not understand -fexcess-precision=standard, the use of
1815 # x87 floating point operations leads to problems like isinf possibly returning
1816 # false for a value that is infinite when converted from the 80bit register to
1817 # the 8byte memory representation.
1819 # Only perform the test if the compiler doesn't understand
1820 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1821 # automatically.
1822 if '-fexcess-precision=standard' not in cflags
1823   if not cc.compiles('''
1824 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1825 choke me
1826 #endif''',
1827       name: '', args: test_c_args)
1828     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1829   endif
1830 endif
1834 ###############################################################
1835 # Compiler flags
1836 ###############################################################
1838 common_functional_flags = [
1839   # Disable strict-aliasing rules; needed for gcc 3.3+
1840   '-fno-strict-aliasing',
1841   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1842   '-fwrapv',
1843   '-fexcess-precision=standard',
1846 cflags += cc.get_supported_arguments(common_functional_flags)
1847 if llvm.found()
1848   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1849 endif
1851 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1852 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1854 common_warning_flags = [
1855   '-Wmissing-prototypes',
1856   '-Wpointer-arith',
1857   # Really don't want VLAs to be used in our dialect of C
1858   '-Werror=vla',
1859   # On macOS, complain about usage of symbols newer than the deployment target
1860   '-Werror=unguarded-availability-new',
1861   '-Wendif-labels',
1862   '-Wmissing-format-attribute',
1863   '-Wimplicit-fallthrough=3',
1864   '-Wcast-function-type',
1865   '-Wshadow=compatible-local',
1866   # This was included in -Wall/-Wformat in older GCC versions
1867   '-Wformat-security',
1870 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1871 if llvm.found()
1872   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1873 endif
1875 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1876 # the result for them
1877 cflags_no_decl_after_statement = []
1878 if cc.has_argument('-Wdeclaration-after-statement')
1879   cflags_warn += '-Wdeclaration-after-statement'
1880   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1881 endif
1884 # The following tests want to suppress various unhelpful warnings by adding
1885 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1886 # switches, so we have to test for the positive form and if that works,
1887 # add the negative form.
1889 negative_warning_flags = [
1890   # Suppress clang's unhelpful unused-command-line-argument warnings.
1891   'unused-command-line-argument',
1893   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1894   # of warnings when building plperl because of usages in the Perl headers.
1895   'compound-token-split-by-macro',
1897   # Similarly disable useless truncation warnings from gcc 8+
1898   'format-truncation',
1899   'stringop-truncation',
1901   # Suppress clang 16's strict warnings about function casts
1902   'cast-function-type-strict',
1904   # To make warning_level=2 / -Wextra work, we'd need at least the following
1905   # 'clobbered',
1906   # 'missing-field-initializers',
1907   # 'sign-compare',
1908   # 'unused-parameter',
1911 foreach w : negative_warning_flags
1912   if cc.has_argument('-W' + w)
1913     cflags_warn += '-Wno-' + w
1914   endif
1915   if llvm.found() and cpp.has_argument('-W' + w)
1916     cxxflags_warn += '-Wno-' + w
1917   endif
1918 endforeach
1921 if cc.get_id() == 'msvc'
1922   cflags_warn += [
1923     '/wd4018', # signed/unsigned mismatch
1924     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1925     '/wd4273', # inconsistent DLL linkage
1926     '/wd4101', # unreferenced local variable
1927     '/wd4102', # unreferenced label
1928     '/wd4090', # different 'modifier' qualifiers
1929     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1930   ]
1932   cppflags += [
1933     '/DWIN32',
1934     '/DWINDOWS',
1935     '/D__WINDOWS__',
1936     '/D__WIN32__',
1937     '/D_CRT_SECURE_NO_DEPRECATE',
1938     '/D_CRT_NONSTDC_NO_DEPRECATE',
1939   ]
1941   # We never need export libraries. As link.exe reports their creation, they
1942   # are unnecessarily noisy. Similarly, we don't need import library for
1943   # modules, we only import them dynamically, and they're also noisy.
1944   ldflags += '/NOEXP'
1945   ldflags_mod += '/NOIMPLIB'
1946 endif
1949 # Compute flags that are built into Meson.  We need these to
1950 # substitute into Makefile.global and for pg_config.  We only compute
1951 # the flags for Unix-style compilers, since that's the only style that
1952 # would use Makefile.global or pg_config.
1954 # We don't use get_option('warning_level') here, because the other
1955 # warning levels are not useful with PostgreSQL source code.
1956 common_builtin_flags = ['-Wall']
1958 if get_option('debug')
1959   common_builtin_flags += ['-g']
1960 endif
1962 optimization = get_option('optimization')
1963 if optimization == '0'
1964   common_builtin_flags += ['-O0']
1965 elif optimization == '1'
1966   common_builtin_flags += ['-O1']
1967 elif optimization == '2'
1968   common_builtin_flags += ['-O2']
1969 elif optimization == '3'
1970   common_builtin_flags += ['-O3']
1971 elif optimization == 's'
1972   common_builtin_flags += ['-Os']
1973 endif
1975 cflags_builtin = cc.get_supported_arguments(common_builtin_flags)
1976 if llvm.found()
1977   cxxflags_builtin = cpp.get_supported_arguments(common_builtin_flags)
1978 endif
1982 ###############################################################
1983 # Atomics
1984 ###############################################################
1986 if not get_option('spinlocks')
1987   warning('Not using spinlocks will cause poor performance')
1988 else
1989   cdata.set('HAVE_SPINLOCKS', 1)
1990 endif
1992 if not get_option('atomics')
1993   warning('Not using atomics will cause poor performance')
1994 else
1995   # XXX: perhaps we should require some atomics support in this case these
1996   # days?
1997   cdata.set('HAVE_ATOMICS', 1)
1999   atomic_checks = [
2000     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2001      'desc': '__sync_lock_test_and_set(char)',
2002      'test': '''
2003 char lock = 0;
2004 __sync_lock_test_and_set(&lock, 1);
2005 __sync_lock_release(&lock);'''},
2007     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2008      'desc': '__sync_lock_test_and_set(int32)',
2009      'test': '''
2010 int lock = 0;
2011 __sync_lock_test_and_set(&lock, 1);
2012 __sync_lock_release(&lock);'''},
2014     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2015      'desc': '__sync_val_compare_and_swap(int32)',
2016      'test': '''
2017 int val = 0;
2018 __sync_val_compare_and_swap(&val, 0, 37);'''},
2020     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2021      'desc': '__sync_val_compare_and_swap(int64)',
2022      'test': '''
2023 INT64 val = 0;
2024 __sync_val_compare_and_swap(&val, 0, 37);'''},
2026     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2027      'desc': ' __atomic_compare_exchange_n(int32)',
2028      'test': '''
2029 int val = 0;
2030 int expect = 0;
2031 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2033     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2034      'desc': ' __atomic_compare_exchange_n(int64)',
2035      'test': '''
2036 INT64 val = 0;
2037 INT64 expect = 0;
2038 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2039   ]
2041   foreach check : atomic_checks
2042     test = '''
2043 int main(void)
2046 }'''.format(check['test'])
2048     cdata.set(check['name'],
2049       cc.links(test,
2050         name: check['desc'],
2051         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
2052     )
2053   endforeach
2055 endif
2058 ###############################################################
2059 # Check for the availability of XSAVE intrinsics.
2060 ###############################################################
2062 cflags_xsave = []
2063 if host_cpu == 'x86' or host_cpu == 'x86_64'
2065   prog = '''
2066 #include <immintrin.h>
2068 int main(void)
2070     return _xgetbv(0) & 0xe0;
2074   if cc.links(prog, name: 'XSAVE intrinsics without -mxsave',
2075         args: test_c_args)
2076     cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2077   elif cc.links(prog, name: 'XSAVE intrinsics with -mxsave',
2078         args: test_c_args + ['-mxsave'])
2079     cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2080     cflags_xsave += '-mxsave'
2081   endif
2083 endif
2086 ###############################################################
2087 # Check for the availability of AVX-512 popcount intrinsics.
2088 ###############################################################
2090 cflags_popcnt = []
2091 if host_cpu == 'x86_64'
2093   prog = '''
2094 #include <immintrin.h>
2096 int main(void)
2098     const char buf[sizeof(__m512i)];
2099     INT64 popcnt = 0;
2100     __m512i accum = _mm512_setzero_si512();
2101     const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2102     const __m512i cnt = _mm512_popcnt_epi64(val);
2103     accum = _mm512_add_epi64(accum, cnt);
2104     popcnt = _mm512_reduce_add_epi64(accum);
2105     /* return computed value, to prevent the above being optimized away */
2106     return popcnt == 0;
2110   if cc.links(prog, name: 'AVX-512 popcount without -mavx512vpopcntdq -mavx512bw',
2111         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))])
2112     cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2113   elif cc.links(prog, name: 'AVX-512 popcount with -mavx512vpopcntdq -mavx512bw',
2114         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))] + ['-mavx512vpopcntdq'] + ['-mavx512bw'])
2115     cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2116     cflags_popcnt += ['-mavx512vpopcntdq'] + ['-mavx512bw']
2117   endif
2119 endif
2122 ###############################################################
2123 # Select CRC-32C implementation.
2125 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2126 # use the special CRC instructions for calculating CRC-32C. If we're not
2127 # targeting such a processor, but we can nevertheless produce code that uses
2128 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
2129 # implementations and select which one to use at runtime, depending on whether
2130 # SSE 4.2 is supported by the processor we're running on.
2132 # Similarly, if we are targeting an ARM processor that has the CRC
2133 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2134 # we're not targeting such a processor, but can nevertheless produce code that
2135 # uses the CRC instructions, compile both, and select at runtime.
2136 ###############################################################
2138 have_optimized_crc = false
2139 cflags_crc = []
2140 if host_cpu == 'x86' or host_cpu == 'x86_64'
2142   if cc.get_id() == 'msvc'
2143     cdata.set('USE_SSE42_CRC32C', false)
2144     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2145     have_optimized_crc = true
2146   else
2148     prog = '''
2149 #include <nmmintrin.h>
2151 int main(void)
2153     unsigned int crc = 0;
2154     crc = _mm_crc32_u8(crc, 0);
2155     crc = _mm_crc32_u32(crc, 0);
2156     /* return computed value, to prevent the above being optimized away */
2157     return crc == 0;
2161     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2162           args: test_c_args)
2163       # Use Intel SSE 4.2 unconditionally.
2164       cdata.set('USE_SSE42_CRC32C', 1)
2165       have_optimized_crc = true
2166     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2167           args: test_c_args + ['-msse4.2'])
2168       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2169       # the runtime check.
2170       cflags_crc += '-msse4.2'
2171       cdata.set('USE_SSE42_CRC32C', false)
2172       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2173       have_optimized_crc = true
2174     endif
2176   endif
2178 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2180   prog = '''
2181 #include <arm_acle.h>
2183 int main(void)
2185     unsigned int crc = 0;
2186     crc = __crc32cb(crc, 0);
2187     crc = __crc32ch(crc, 0);
2188     crc = __crc32cw(crc, 0);
2189     crc = __crc32cd(crc, 0);
2191     /* return computed value, to prevent the above being optimized away */
2192     return crc == 0;
2196   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2197       args: test_c_args)
2198     # Use ARM CRC Extension unconditionally
2199     cdata.set('USE_ARMV8_CRC32C', 1)
2200     have_optimized_crc = true
2201   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2202       args: test_c_args + ['-march=armv8-a+crc'])
2203     # Use ARM CRC Extension, with runtime check
2204     cflags_crc += '-march=armv8-a+crc'
2205     cdata.set('USE_ARMV8_CRC32C', false)
2206     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2207     have_optimized_crc = true
2208   endif
2210 elif host_cpu == 'loongarch64'
2212   prog = '''
2213 int main(void)
2215     unsigned int crc = 0;
2216     crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2217     crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2218     crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2219     crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2221     /* return computed value, to prevent the above being optimized away */
2222     return crc == 0;
2226   if cc.links(prog, name: '__builtin_loongarch_crcc_w_b_w, __builtin_loongarch_crcc_w_h_w, __builtin_loongarch_crcc_w_w_w, and __builtin_loongarch_crcc_w_d_w',
2227       args: test_c_args)
2228     # Use LoongArch CRC instruction unconditionally
2229     cdata.set('USE_LOONGARCH_CRC32C', 1)
2230     have_optimized_crc = true
2231   endif
2233 endif
2235 if not have_optimized_crc
2236   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2237   # support.
2238   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2239 endif
2243 ###############################################################
2244 # Other CPU specific stuff
2245 ###############################################################
2247 if host_cpu == 'x86_64'
2249   if cc.compiles('''
2250       void main(void)
2251       {
2252           long long x = 1; long long r;
2253           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2254       }''',
2255       name: '@0@: popcntq instruction'.format(host_cpu),
2256       args: test_c_args)
2257     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2258   endif
2260 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2261   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2262   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2263     if cc.compiles('''
2264       static inline int
2265       addi(int ra, int si)
2266       {
2267           int res = 0;
2268           if (__builtin_constant_p(si))
2269               __asm__ __volatile__(
2270                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2271           return res;
2272       }
2273       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2274       ''',
2275       args: test_c_args)
2276       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2277     endif
2278   endif
2279 endif
2283 ###############################################################
2284 # Library / OS tests
2285 ###############################################################
2287 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2288 # unnecessary checks over and over, particularly on windows.
2289 header_checks = [
2290   'atomic.h',
2291   'copyfile.h',
2292   'crtdefs.h',
2293   'execinfo.h',
2294   'getopt.h',
2295   'ifaddrs.h',
2296   'langinfo.h',
2297   'mbarrier.h',
2298   'stdbool.h',
2299   'strings.h',
2300   'sys/epoll.h',
2301   'sys/event.h',
2302   'sys/personality.h',
2303   'sys/prctl.h',
2304   'sys/procctl.h',
2305   'sys/signalfd.h',
2306   'sys/ucred.h',
2307   'termios.h',
2308   'ucred.h',
2311 foreach header : header_checks
2312   varname = 'HAVE_' + header.underscorify().to_upper()
2314   # Emulate autoconf behaviour of not-found->undef, found->1
2315   found = cc.has_header(header,
2316     include_directories: postgres_inc, args: test_c_args)
2317   cdata.set(varname, found ? 1 : false,
2318             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2319 endforeach
2322 decl_checks = [
2323   ['F_FULLFSYNC', 'fcntl.h'],
2324   ['fdatasync', 'unistd.h'],
2325   ['posix_fadvise', 'fcntl.h'],
2326   ['strlcat', 'string.h'],
2327   ['strlcpy', 'string.h'],
2328   ['strnlen', 'string.h'],
2331 # Need to check for function declarations for these functions, because
2332 # checking for library symbols wouldn't handle deployment target
2333 # restrictions on macOS
2334 decl_checks += [
2335   ['preadv', 'sys/uio.h'],
2336   ['pwritev', 'sys/uio.h'],
2339 # Check presence of some optional LLVM functions.
2340 if llvm.found()
2341   decl_checks += [
2342     ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2343     ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2344   ]
2345 endif
2347 foreach c : decl_checks
2348   func = c.get(0)
2349   header = c.get(1)
2350   args = c.get(2, {})
2351   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2353   found = cc.has_header_symbol(header, func,
2354     args: test_c_args, include_directories: postgres_inc,
2355     kwargs: args)
2356   cdata.set10(varname, found, description:
2357 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2358    don't.'''.format(func))
2359 endforeach
2362 if cc.has_type('struct option',
2363     args: test_c_args, include_directories: postgres_inc,
2364     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2365   cdata.set('HAVE_STRUCT_OPTION', 1)
2366 endif
2369 foreach c : ['opterr', 'optreset']
2370   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2372   if cc.links('''
2373 #include <unistd.h>
2374 int main(void)
2376     extern int @0@;
2377     @0@ = 1;
2379 '''.format(c), name: c, args: test_c_args)
2380     cdata.set(varname, 1)
2381   else
2382     cdata.set(varname, false)
2383   endif
2384 endforeach
2386 if cc.has_type('socklen_t',
2387     args: test_c_args, include_directories: postgres_inc,
2388     prefix: '''
2389 #include <sys/socket.h>''')
2390   cdata.set('HAVE_SOCKLEN_T', 1)
2391 endif
2393 if cc.has_member('struct sockaddr', 'sa_len',
2394     args: test_c_args, include_directories: postgres_inc,
2395     prefix: '''
2396 #include <sys/types.h>
2397 #include <sys/socket.h>''')
2398   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2399 endif
2401 if cc.has_member('struct tm', 'tm_zone',
2402     args: test_c_args, include_directories: postgres_inc,
2403     prefix: '''
2404 #include <sys/types.h>
2405 #include <time.h>
2406 ''')
2407   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2408 endif
2410 if cc.compiles('''
2411 #include <time.h>
2412 extern int foo(void);
2413 int foo(void)
2415     return timezone / 60;
2417 ''',
2418     name: 'global variable `timezone\' exists',
2419     args: test_c_args, include_directories: postgres_inc)
2420   cdata.set('HAVE_INT_TIMEZONE', 1)
2421 else
2422   cdata.set('HAVE_INT_TIMEZONE', false)
2423 endif
2425 if cc.has_type('union semun',
2426     args: test_c_args,
2427     include_directories: postgres_inc,
2428     prefix: '''
2429 #include <sys/types.h>
2430 #include <sys/ipc.h>
2431 #include <sys/sem.h>
2432 ''')
2433   cdata.set('HAVE_UNION_SEMUN', 1)
2434 endif
2436 if cc.compiles('''
2437 #include <string.h>
2438 int main(void)
2440   char buf[100];
2441   switch (strerror_r(1, buf, sizeof(buf)))
2442   { case 0: break; default: break; }
2443 }''',
2444     name: 'strerror_r',
2445     args: test_c_args, include_directories: postgres_inc)
2446   cdata.set('STRERROR_R_INT', 1)
2447 else
2448   cdata.set('STRERROR_R_INT', false)
2449 endif
2451 # Find the right header file for the locale_t type.  macOS needs xlocale.h;
2452 # standard is locale.h, but glibc <= 2.25 also had an xlocale.h file that
2453 # we should not use so we check the standard header first.  MSVC has a
2454 # replacement defined in src/include/port/win32_port.h.
2455 if not cc.has_type('locale_t', prefix: '#include <locale.h>') and \
2456    cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2457   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2458 endif
2460 # Check if the C compiler understands typeof or a variant.  Define
2461 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2462 foreach kw : ['typeof', '__typeof__', 'decltype']
2463   if cc.compiles('''
2464 int main(void)
2466     int x = 0;
2467     @0@(x) y;
2468     y = x;
2469     return y;
2471 '''.format(kw),
2472     name: 'typeof()',
2473     args: test_c_args, include_directories: postgres_inc)
2475     cdata.set('HAVE_TYPEOF', 1)
2476     if kw != 'typeof'
2477       cdata.set('typeof', kw)
2478     endif
2480     break
2481   endif
2482 endforeach
2485 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2486 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2487 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2488 wcstombs_l_test = '''
2489 #include <stdlib.h>
2490 #include <locale.h>
2493 void main(void)
2495 #ifndef wcstombs_l
2496     (void) wcstombs_l;
2497 #endif
2500 if (not cc.compiles(wcstombs_l_test.format(''),
2501       name: 'wcstombs_l') and
2502     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2503       name: 'wcstombs_l in xlocale.h'))
2504     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2505 endif
2508 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2509 # understands, because it conflicts with __declspec(restrict). Therefore we
2510 # define pg_restrict to the appropriate definition, which presumably won't
2511 # conflict.
2513 # We assume C99 support, so we don't need to make this conditional.
2514 cdata.set('pg_restrict', '__restrict')
2517 # Most libraries are included only if they demonstrably provide a function we
2518 # need, but libm is an exception: always include it, because there are too
2519 # many compilers that play cute optimization games that will break probes for
2520 # standard functions such as pow().
2521 os_deps += cc.find_library('m', required: false)
2523 rt_dep = cc.find_library('rt', required: false)
2525 dl_dep = cc.find_library('dl', required: false)
2527 util_dep = cc.find_library('util', required: false)
2529 getopt_dep = cc.find_library('getopt', required: false)
2530 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2531 # Check if we want to replace getopt/getopt_long even if provided by the system
2532 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2533 #   so always use our version on Windows
2534 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2535 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2536 # - We want to use system's getopt_long() only if the system provides struct
2537 #   option
2538 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2539 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2541 # Required on BSDs
2542 execinfo_dep = cc.find_library('execinfo', required: false)
2544 if host_system == 'cygwin'
2545   cygipc_dep = cc.find_library('cygipc', required: false)
2546 else
2547   cygipc_dep = not_found_dep
2548 endif
2550 if host_system == 'sunos'
2551   socket_dep = cc.find_library('socket', required: false)
2552 else
2553   socket_dep = not_found_dep
2554 endif
2556 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2557 # unnecessary checks over and over, particularly on windows.
2558 func_checks = [
2559   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2560   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2561   ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2562   ['copyfile'],
2563   ['copy_file_range'],
2564   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2565   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2566   # required. Just checking for dlsym() ought to suffice.
2567   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2568   ['explicit_bzero'],
2569   ['getifaddrs'],
2570   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2571   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2572   ['getpeereid'],
2573   ['getpeerucred'],
2574   ['inet_aton'],
2575   ['inet_pton'],
2576   ['kqueue'],
2577   ['mbstowcs_l'],
2578   ['memset_s'],
2579   ['mkdtemp'],
2580   ['posix_fadvise'],
2581   ['posix_fallocate'],
2582   ['ppoll'],
2583   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2584   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2585   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2586   ['setproctitle', {'dependencies': [util_dep]}],
2587   ['setproctitle_fast'],
2588   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2589   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2590   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2591   ['socket', {'dependencies': [socket_dep], 'define': false}],
2592   ['strchrnul'],
2593   ['strerror_r', {'dependencies': [thread_dep]}],
2594   ['strlcat'],
2595   ['strlcpy'],
2596   ['strnlen'],
2597   ['strsignal'],
2598   ['sync_file_range'],
2599   ['syncfs'],
2600   ['uselocale'],
2601   ['wcstombs_l'],
2604 func_check_results = {}
2605 foreach c : func_checks
2606   func = c.get(0)
2607   kwargs = c.get(1, {})
2608   deps = kwargs.get('dependencies', [])
2610   if kwargs.get('skip', false)
2611     continue
2612   endif
2614   found = cc.has_function(func, args: test_c_args)
2616   if not found
2617     foreach dep : deps
2618       if not dep.found()
2619         continue
2620       endif
2621       found = cc.has_function(func, args: test_c_args,
2622                               dependencies: [dep])
2623       if found
2624         os_deps += dep
2625         break
2626       endif
2627     endforeach
2628   endif
2630   func_check_results += {func: found}
2632   if kwargs.get('define', true)
2633     # Emulate autoconf behaviour of not-found->undef, found->1
2634     cdata.set('HAVE_' + func.underscorify().to_upper(),
2635               found  ? 1 : false,
2636               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2637   endif
2638 endforeach
2641 if cc.has_function('syslog', args: test_c_args) and \
2642     cc.check_header('syslog.h', args: test_c_args)
2643   cdata.set('HAVE_SYSLOG', 1)
2644 endif
2647 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2648 # semaphores
2649 if sema_kind == 'unnamed_posix' and \
2650    not func_check_results.get('sem_init', false)
2651   sema_kind = 'sysv'
2652 endif
2654 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2655 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2657 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2658 cdata.set_quoted('DLSUFFIX', dlsuffix)
2661 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2662 cdata.set_quoted('PG_VERSION_STR',
2663   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2664     pg_version, host_machine.cpu_family(), host_system,
2665     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2666   )
2670 ###############################################################
2671 # NLS / Gettext
2672 ###############################################################
2674 nlsopt = get_option('nls')
2675 libintl = not_found_dep
2677 if not nlsopt.disabled()
2678   # otherwise there'd be lots of
2679   # "Gettext not found, all translation (po) targets will be ignored."
2680   # warnings if not found.
2681   msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2683   # meson 0.59 has this wrapped in dependency('intl')
2684   if (msgfmt.found() and
2685       cc.check_header('libintl.h', required: nlsopt,
2686         args: test_c_args, include_directories: postgres_inc))
2688     # in libc
2689     if cc.has_function('ngettext')
2690       libintl = declare_dependency()
2691     else
2692       libintl = cc.find_library('intl',
2693         has_headers: ['libintl.h'], required: nlsopt,
2694         header_include_directories: postgres_inc,
2695         dirs: test_lib_d)
2696     endif
2697   endif
2699   if libintl.found()
2700     i18n = import('i18n')
2701     cdata.set('ENABLE_NLS', 1)
2702   endif
2703 endif
2707 ###############################################################
2708 # Build
2709 ###############################################################
2711 # Set up compiler / linker arguments to be used everywhere, individual targets
2712 # can add further args directly, or indirectly via dependencies
2713 add_project_arguments(cflags, language: ['c'])
2714 add_project_arguments(cppflags, language: ['c'])
2715 add_project_arguments(cflags_warn, language: ['c'])
2716 add_project_arguments(cxxflags, language: ['cpp'])
2717 add_project_arguments(cppflags, language: ['cpp'])
2718 add_project_arguments(cxxflags_warn, language: ['cpp'])
2719 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2722 # Collect a number of lists of things while recursing through the source
2723 # tree. Later steps then can use those.
2725 # list of targets for various alias targets
2726 backend_targets = []
2727 bin_targets = []
2728 pl_targets = []
2729 contrib_targets = []
2730 testprep_targets = []
2731 nls_targets = []
2734 # Define the tests to distribute them to the correct test styles later
2735 test_deps = []
2736 tests = []
2739 # Default options for targets
2741 # First identify rpaths
2742 bin_install_rpaths = []
2743 lib_install_rpaths = []
2744 mod_install_rpaths = []
2747 # Don't add rpaths on darwin for now - as long as only absolute references to
2748 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2749 # their final destination.
2750 if host_system != 'darwin'
2751   # Add absolute path to libdir to rpath. This ensures installed binaries /
2752   # libraries find our libraries (mainly libpq).
2753   bin_install_rpaths += dir_prefix / dir_lib
2754   lib_install_rpaths += dir_prefix / dir_lib
2755   mod_install_rpaths += dir_prefix / dir_lib
2757   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2758   #
2759   # Not needed on darwin even if we use relative rpaths for our own libraries,
2760   # as the install_name of libraries in extra_lib_dirs will point to their
2761   # location anyway.
2762   bin_install_rpaths += postgres_lib_d
2763   lib_install_rpaths += postgres_lib_d
2764   mod_install_rpaths += postgres_lib_d
2765 endif
2768 # Define arguments for default targets
2770 default_target_args = {
2771   'implicit_include_directories': false,
2772   'install': true,
2775 default_lib_args = default_target_args + {
2776   'name_prefix': '',
2779 internal_lib_args = default_lib_args + {
2780   'build_by_default': false,
2781   'install': false,
2784 default_mod_args = default_lib_args + {
2785   'name_prefix': '',
2786   'install_dir': dir_lib_pkg,
2789 default_bin_args = default_target_args + {
2790   'install_dir': dir_bin,
2793 if get_option('rpath')
2794   default_lib_args += {
2795     'install_rpath': ':'.join(lib_install_rpaths),
2796   }
2798   default_mod_args += {
2799     'install_rpath': ':'.join(mod_install_rpaths),
2800   }
2802   default_bin_args += {
2803     'install_rpath': ':'.join(bin_install_rpaths),
2804   }
2805 endif
2808 # Helper for exporting a limited number of symbols
2809 gen_export_kwargs = {
2810   'input': 'exports.txt',
2811   'output': '@BASENAME@.'+export_file_suffix,
2812   'command': [perl, files('src/tools/gen_export.pl'),
2813    '--format', export_file_format,
2814    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2815   'build_by_default': false,
2816   'install': false,
2822 ### Helpers for custom targets used across the tree
2825 catalog_pm = files('src/backend/catalog/Catalog.pm')
2826 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2827 gen_kwlist_deps = [perfect_hash_pm]
2828 gen_kwlist_cmd = [
2829   perl, '-I', '@SOURCE_ROOT@/src/tools',
2830   files('src/tools/gen_keywordlist.pl'),
2831   '--output', '@OUTDIR@', '@INPUT@']
2836 ### windows resources related stuff
2839 if host_system == 'windows'
2840   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2841   win32ver_rc = files('src/port/win32ver.rc')
2842   rcgen = find_program('src/tools/rcgen', native: true)
2844   rcgen_base_args = [
2845     '--srcdir', '@SOURCE_DIR@',
2846     '--builddir', meson.build_root(),
2847     '--rcout', '@OUTPUT0@',
2848     '--out', '@OUTPUT1@',
2849     '--input', '@INPUT@',
2850     '@EXTRA_ARGS@',
2851   ]
2853   if cc.get_argument_syntax() == 'msvc'
2854     rc = find_program('rc', required: true)
2855     rcgen_base_args += ['--rc', rc.path()]
2856     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2857   else
2858     windres = find_program('windres', required: true)
2859     rcgen_base_args += ['--windres', windres.path()]
2860     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2861   endif
2863   # msbuild backend doesn't support this atm
2864   if meson.backend() == 'ninja'
2865     rcgen_base_args += ['--depfile', '@DEPFILE@']
2866   endif
2868   rcgen_bin_args = rcgen_base_args + [
2869     '--VFT_TYPE', 'VFT_APP',
2870     '--FILEENDING', 'exe',
2871     '--ICO', pg_ico
2872   ]
2874   rcgen_lib_args = rcgen_base_args + [
2875     '--VFT_TYPE', 'VFT_DLL',
2876     '--FILEENDING', 'dll',
2877   ]
2879   rc_bin_gen = generator(rcgen,
2880     depfile: '@BASENAME@.d',
2881     arguments: rcgen_bin_args,
2882     output: rcgen_outputs,
2883   )
2885   rc_lib_gen = generator(rcgen,
2886     depfile: '@BASENAME@.d',
2887     arguments: rcgen_lib_args,
2888     output: rcgen_outputs,
2889   )
2890 endif
2894 # headers that the whole build tree depends on
2895 generated_headers = []
2896 # headers that the backend build depends on
2897 generated_backend_headers = []
2898 # configure_files() output, needs a way of converting to file names
2899 configure_files = []
2901 # generated files that might conflict with a partial in-tree autoconf build
2902 generated_sources = []
2903 # same, for paths that differ between autoconf / meson builds
2904 # elements are [dir, [files]]
2905 generated_sources_ac = {}
2908 # First visit src/include - all targets creating headers are defined
2909 # within. That makes it easy to add the necessary dependencies for the
2910 # subsequent build steps.
2912 subdir('src/include')
2914 subdir('config')
2916 # Then through src/port and src/common, as most other things depend on them
2918 frontend_port_code = declare_dependency(
2919   compile_args: ['-DFRONTEND'],
2920   include_directories: [postgres_inc],
2921   dependencies: os_deps,
2924 backend_port_code = declare_dependency(
2925   compile_args: ['-DBUILDING_DLL'],
2926   include_directories: [postgres_inc],
2927   sources: [errcodes], # errcodes.h is needed due to use of ereport
2928   dependencies: os_deps,
2931 subdir('src/port')
2933 frontend_common_code = declare_dependency(
2934   compile_args: ['-DFRONTEND'],
2935   include_directories: [postgres_inc],
2936   sources: generated_headers,
2937   dependencies: [os_deps, zlib, zstd],
2940 backend_common_code = declare_dependency(
2941   compile_args: ['-DBUILDING_DLL'],
2942   include_directories: [postgres_inc],
2943   sources: generated_headers,
2944   dependencies: [os_deps, zlib, zstd],
2947 subdir('src/common')
2949 # all shared libraries should depend on shlib_code
2950 shlib_code = declare_dependency(
2951   link_args: ldflags_sl,
2954 # all static libraries not part of the backend should depend on this
2955 frontend_stlib_code = declare_dependency(
2956   include_directories: [postgres_inc],
2957   link_with: [common_static, pgport_static],
2958   sources: generated_headers,
2959   dependencies: [os_deps, libintl],
2962 # all shared libraries not part of the backend should depend on this
2963 frontend_shlib_code = declare_dependency(
2964   include_directories: [postgres_inc],
2965   link_with: [common_shlib, pgport_shlib],
2966   sources: generated_headers,
2967   dependencies: [shlib_code, os_deps, libintl],
2970 # Dependencies both for static and shared libpq
2971 libpq_deps += [
2972   thread_dep,
2974   gssapi,
2975   ldap_r,
2976   libintl,
2977   ssl,
2980 subdir('src/interfaces/libpq')
2981 # fe_utils depends on libpq
2982 subdir('src/fe_utils')
2984 # for frontend binaries
2985 frontend_code = declare_dependency(
2986   include_directories: [postgres_inc],
2987   link_with: [fe_utils, common_static, pgport_static],
2988   sources: generated_headers,
2989   dependencies: [os_deps, libintl],
2992 backend_both_deps += [
2993   thread_dep,
2994   bsd_auth,
2995   gssapi,
2996   icu,
2997   icu_i18n,
2998   ldap,
2999   libintl,
3000   libxml,
3001   lz4,
3002   pam,
3003   ssl,
3004   systemd,
3005   zlib,
3006   zstd,
3009 backend_mod_deps = backend_both_deps + os_deps
3011 backend_code = declare_dependency(
3012   compile_args: ['-DBUILDING_DLL'],
3013   include_directories: [postgres_inc],
3014   link_args: ldflags_be,
3015   link_with: [],
3016   sources: generated_headers + generated_backend_headers,
3017   dependencies: os_deps + backend_both_deps + backend_deps,
3020 # install these files only during test, not main install
3021 test_install_data = []
3022 test_install_libs = []
3024 # src/backend/meson.build defines backend_mod_code used for extension
3025 # libraries.
3028 # Then through the main sources. That way contrib can have dependencies on
3029 # main sources. Note that this explicitly doesn't enter src/test, right now a
3030 # few regression tests depend on contrib files.
3032 subdir('src')
3034 subdir('contrib')
3036 subdir('src/test')
3037 subdir('src/interfaces/libpq/test')
3038 subdir('src/interfaces/ecpg/test')
3040 subdir('doc/src/sgml')
3042 generated_sources_ac += {'': ['GNUmakefile']}
3044 # After processing src/test, add test_install_libs to the testprep_targets
3045 # to build them
3046 testprep_targets += test_install_libs
3049 # If there are any files in the source directory that we also generate in the
3050 # build directory, they might get preferred over the newly generated files,
3051 # e.g. because of a #include "file", which always will search in the current
3052 # directory first.
3053 message('checking for file conflicts between source and build directory')
3054 conflicting_files = []
3055 potentially_conflicting_files_t = []
3056 potentially_conflicting_files_t += generated_headers
3057 potentially_conflicting_files_t += generated_backend_headers
3058 potentially_conflicting_files_t += generated_backend_sources
3059 potentially_conflicting_files_t += generated_sources
3061 potentially_conflicting_files = []
3063 # convert all sources of potentially conflicting files into uniform shape
3064 foreach t : potentially_conflicting_files_t
3065   potentially_conflicting_files += t.full_path()
3066 endforeach
3067 foreach t1 : configure_files
3068   if meson.version().version_compare('>=0.59')
3069     t = fs.parent(t1) / fs.name(t1)
3070   else
3071     t = '@0@'.format(t1)
3072   endif
3073   potentially_conflicting_files += meson.current_build_dir() / t
3074 endforeach
3075 foreach sub, fnames : generated_sources_ac
3076   sub = meson.build_root() / sub
3077   foreach fname : fnames
3078     potentially_conflicting_files += sub / fname
3079   endforeach
3080 endforeach
3082 # find and report conflicting files
3083 foreach build_path : potentially_conflicting_files
3084   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3085   # str.replace is in 0.56
3086   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3087   if fs.exists(src_path) or fs.is_symlink(src_path)
3088     conflicting_files += src_path
3089   endif
3090 endforeach
3091 # XXX: Perhaps we should generate a file that would clean these up? The list
3092 # can be long.
3093 if conflicting_files.length() > 0
3094   errmsg_cleanup = '''
3095 Conflicting files in source directory:
3096   @0@
3098 The conflicting files need to be removed, either by removing the files listed
3099 above, or by running configure and then make maintainer-clean.
3101   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3102   error(errmsg_nonclean_base.format(errmsg_cleanup))
3103 endif
3107 ###############################################################
3108 # Install targets
3109 ###############################################################
3112 # We want to define additional install targets beyond what meson provides. For
3113 # that we need to define targets depending on nearly everything. We collected
3114 # the results of i18n.gettext() invocations into nls_targets, that also
3115 # includes maintainer targets though. Collect the ones we want as a dependency.
3117 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3118 # generation happens during install, so that's not a real issue.
3119 nls_mo_targets = []
3120 if libintl.found() and meson.version().version_compare('>=0.60')
3121   # use range() to avoid the flattening of the list that foreach() would do
3122   foreach off : range(0, nls_targets.length())
3123     # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3124     # -pot target 3) maintainer -pot target
3125     nls_mo_targets += nls_targets[off][0]
3126   endforeach
3127   alias_target('nls', nls_mo_targets)
3128 endif
3131 all_built = [
3132   backend_targets,
3133   bin_targets,
3134   libpq_st,
3135   pl_targets,
3136   contrib_targets,
3137   nls_mo_targets,
3138   testprep_targets,
3139   ecpg_targets,
3142 # Meson's default install target is quite verbose. Provide one that is quiet.
3143 install_quiet = custom_target('install-quiet',
3144   output: 'install-quiet',
3145   build_always_stale: true,
3146   build_by_default: false,
3147   command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3148   depends: all_built,
3151 # Target to install files used for tests, which aren't installed by default
3152 install_test_files_args = [
3153   install_files,
3154   '--prefix', dir_prefix,
3155   '--install', contrib_data_dir, test_install_data,
3156   '--install', dir_lib_pkg, test_install_libs,
3158 run_target('install-test-files',
3159   command: [python] + install_test_files_args,
3160   depends: testprep_targets,
3165 ###############################################################
3166 # Test prep
3167 ###############################################################
3169 # DESTDIR for the installation we'll run tests in
3170 test_install_destdir = meson.build_root() / 'tmp_install/'
3172 # DESTDIR + prefix appropriately munged
3173 if build_system != 'windows'
3174   # On unixoid systems this is trivial, we just prepend the destdir
3175   assert(dir_prefix.startswith('/')) # enforced by meson
3176   test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3177 else
3178   # drives, drive-relative paths, etc make this complicated on windows, call
3179   # into a copy of meson's logic for it
3180   command = [
3181     python, '-c',
3182     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3183     test_install_destdir, dir_prefix]
3184   test_install_location = run_command(command, check: true).stdout().strip()
3185 endif
3187 meson_install_args = meson_args + ['install'] + {
3188     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3189     'muon': []
3190 }[meson_impl]
3192 # setup tests should be run first,
3193 # so define priority for these
3194 setup_tests_priority = 100
3195 test('tmp_install',
3196     meson_bin, args: meson_install_args ,
3197     env: {'DESTDIR':test_install_destdir},
3198     priority: setup_tests_priority,
3199     timeout: 300,
3200     is_parallel: false,
3201     suite: ['setup'])
3203 test('install_test_files',
3204     python,
3205     args: install_test_files_args + ['--destdir', test_install_destdir],
3206     priority: setup_tests_priority,
3207     is_parallel: false,
3208     suite: ['setup'])
3210 test_result_dir = meson.build_root() / 'testrun'
3213 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3214 # inevitable conflicts from running tests in parallel, hackishly assign
3215 # different ports for different tests.
3217 testport = 40000
3219 test_env = environment()
3221 temp_install_bindir = test_install_location / get_option('bindir')
3222 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3223 test_env.set('PG_REGRESS', pg_regress.full_path())
3224 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3225 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3227 # Test suites that are not safe by default but can be run if selected
3228 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3229 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3230 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3232 # Add the temporary installation to the library search path on platforms where
3233 # that works (everything but windows, basically). On windows everything
3234 # library-like gets installed into bindir, solving that issue.
3235 if library_path_var != ''
3236   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3237 endif
3240 # Create (and remove old) initdb template directory. Tests use that, where
3241 # possible, to make it cheaper to run tests.
3243 # Use python to remove the old cached initdb, as we cannot rely on a working
3244 # 'rm' binary on windows.
3245 test('initdb_cache',
3246      python,
3247      args: [
3248        '-c', '''
3249 import shutil
3250 import sys
3251 import subprocess
3253 shutil.rmtree(sys.argv[1], ignore_errors=True)
3254 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3255 sys.exit(sp.returncode)
3256 ''',
3257        test_initdb_template,
3258        temp_install_bindir / 'initdb',
3259        '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3260        '--no-clean'
3261      ],
3262      priority: setup_tests_priority - 1,
3263      timeout: 300,
3264      is_parallel: false,
3265      env: test_env,
3266      suite: ['setup'])
3270 ###############################################################
3271 # Test Generation
3272 ###############################################################
3274 # When using a meson version understanding exclude_suites, define a
3275 # 'tmp_install' test setup (the default) that excludes tests running against a
3276 # pre-existing install and a 'running' setup that conflicts with creation of
3277 # the temporary installation and tap tests (which don't support running
3278 # against a running server).
3280 running_suites = []
3281 install_suites = []
3282 if meson.version().version_compare('>=0.57')
3283   runningcheck = true
3284 else
3285   runningcheck = false
3286 endif
3288 testwrap = files('src/tools/testwrap')
3290 foreach test_dir : tests
3291   testwrap_base = [
3292     testwrap,
3293     '--basedir', meson.build_root(),
3294     '--srcdir', test_dir['sd'],
3295   ]
3297   foreach kind, v : test_dir
3298     if kind in ['sd', 'bd', 'name']
3299       continue
3300     endif
3302     t = test_dir[kind]
3304     if kind in ['regress', 'isolation', 'ecpg']
3305       if kind == 'regress'
3306         runner = pg_regress
3307         fallback_dbname = 'regression_@0@'
3308       elif kind == 'isolation'
3309         runner = pg_isolation_regress
3310         fallback_dbname = 'isolation_regression_@0@'
3311       elif kind == 'ecpg'
3312         runner = pg_regress_ecpg
3313         fallback_dbname = 'ecpg_regression_@0@'
3314       endif
3316       test_group = test_dir['name']
3317       test_group_running = test_dir['name'] + '-running'
3319       test_output = test_result_dir / test_group / kind
3320       test_output_running = test_result_dir / test_group_running/ kind
3322       # Unless specified by the test, choose a non-conflicting database name,
3323       # to avoid conflicts when running against existing server.
3324       dbname = t.get('dbname',
3325         fallback_dbname.format(test_dir['name']))
3327       test_command_base = [
3328         runner.full_path(),
3329         '--inputdir', t.get('inputdir', test_dir['sd']),
3330         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3331         '--bindir', '',
3332         '--dlpath', test_dir['bd'],
3333         '--max-concurrent-tests=20',
3334         '--dbname', dbname,
3335       ] + t.get('regress_args', [])
3337       test_selection = []
3338       if t.has_key('schedule')
3339         test_selection += ['--schedule', t['schedule'],]
3340       endif
3342       if kind == 'isolation'
3343         test_selection += t.get('specs', [])
3344       else
3345         test_selection += t.get('sql', [])
3346       endif
3348       env = test_env
3349       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3351       test_kwargs = {
3352         'protocol': 'tap',
3353         'priority': 10,
3354         'timeout': 1000,
3355         'depends': test_deps + t.get('deps', []),
3356         'env': env,
3357       } + t.get('test_kwargs', {})
3359       test(test_group / kind,
3360         python,
3361         args: [
3362           testwrap_base,
3363           '--testgroup', test_group,
3364           '--testname', kind,
3365           '--',
3366           test_command_base,
3367           '--outputdir', test_output,
3368           '--temp-instance', test_output / 'tmp_check',
3369           '--port', testport.to_string(),
3370           test_selection,
3371         ],
3372         suite: test_group,
3373         kwargs: test_kwargs,
3374       )
3375       install_suites += test_group
3377       # some tests can't support running against running DB
3378       if runningcheck and t.get('runningcheck', true)
3379         test(test_group_running / kind,
3380           python,
3381           args: [
3382             testwrap_base,
3383             '--testgroup', test_group_running,
3384             '--testname', kind,
3385             '--',
3386             test_command_base,
3387             '--outputdir', test_output_running,
3388             test_selection,
3389           ],
3390           is_parallel: t.get('runningcheck-parallel', true),
3391           suite: test_group_running,
3392           kwargs: test_kwargs,
3393         )
3394         running_suites += test_group_running
3395       endif
3397       testport += 1
3398     elif kind == 'tap'
3399       testwrap_tap = testwrap_base
3400       if not tap_tests_enabled
3401         testwrap_tap += ['--skip', 'TAP tests not enabled']
3402       endif
3404       test_command = [
3405         perl.path(),
3406         '-I', meson.source_root() / 'src/test/perl',
3407         '-I', test_dir['sd'],
3408       ]
3410       # Add temporary install, the build directory for non-installed binaries and
3411       # also test/ for non-installed test binaries built separately.
3412       env = test_env
3413       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3415       foreach name, value : t.get('env', {})
3416         env.set(name, value)
3417       endforeach
3419       test_group = test_dir['name']
3420       test_kwargs = {
3421         'protocol': 'tap',
3422         'suite': test_group,
3423         'timeout': 1000,
3424         'depends': test_deps + t.get('deps', []),
3425         'env': env,
3426       } + t.get('test_kwargs', {})
3428       foreach onetap : t['tests']
3429         # Make tap test names prettier, remove t/ and .pl
3430         onetap_p = onetap
3431         if onetap_p.startswith('t/')
3432           onetap_p = onetap.split('t/')[1]
3433         endif
3434         if onetap_p.endswith('.pl')
3435           onetap_p = fs.stem(onetap_p)
3436         endif
3438         test(test_dir['name'] / onetap_p,
3439           python,
3440           kwargs: test_kwargs,
3441           args: testwrap_tap + [
3442             '--testgroup', test_dir['name'],
3443             '--testname', onetap_p,
3444             '--', test_command,
3445             test_dir['sd'] / onetap,
3446           ],
3447         )
3448       endforeach
3449       install_suites += test_group
3450     else
3451       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3452     endif
3454   endforeach # kinds of tests
3456 endforeach # directories with tests
3458 # repeat condition so meson realizes version dependency
3459 if meson.version().version_compare('>=0.57')
3460   add_test_setup('tmp_install',
3461     is_default: true,
3462     exclude_suites: running_suites)
3463   add_test_setup('running',
3464     exclude_suites: ['setup'] + install_suites)
3465 endif
3469 ###############################################################
3470 # Pseudo targets
3471 ###############################################################
3473 alias_target('backend', backend_targets)
3474 alias_target('bin', bin_targets + [libpq_st])
3475 alias_target('pl', pl_targets)
3476 alias_target('contrib', contrib_targets)
3477 alias_target('testprep', testprep_targets)
3479 alias_target('world', all_built, docs)
3480 alias_target('install-world', install_quiet, installdocs)
3482 run_target('help',
3483   command: [
3484     perl, '-ne', 'next if /^#/; print',
3485     files('doc/src/sgml/targets-meson.txt'),
3486   ]
3491 ###############################################################
3492 # Distribution archive
3493 ###############################################################
3495 # Meson has its own distribution building command (meson dist), but we
3496 # are not using that at this point.  The main problem is that, the way
3497 # they have implemented it, it is not deterministic.  Also, we want it
3498 # to be equivalent to the "make" version for the time being.  But the
3499 # target name "dist" in meson is reserved for that reason, so we call
3500 # the custom target "pgdist".
3502 git = find_program('git', required: false, native: true, disabler: true)
3503 bzip2 = find_program('bzip2', required: false, native: true)
3505 distdir = meson.project_name() + '-' + meson.project_version()
3507 pg_git_revision = get_option('PG_GIT_REVISION')
3509 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3510 # in case the environment has a different setting.  Without this, a
3511 # tarball created on Windows might be different than on, and unusable
3512 # on, Unix machines.
3514 tar_gz = custom_target('tar.gz',
3515   build_always_stale: true,
3516   command: [git, '-C', '@SOURCE_ROOT@',
3517             '-c', 'core.autocrlf=false',
3518             'archive',
3519             '--format', 'tar.gz',
3520             '-9',
3521             '--prefix', distdir + '/',
3522             '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3523             pg_git_revision],
3524   output: distdir + '.tar.gz',
3527 if bzip2.found()
3528   tar_bz2 = custom_target('tar.bz2',
3529     build_always_stale: true,
3530     command: [git, '-C', '@SOURCE_ROOT@',
3531               '-c', 'core.autocrlf=false',
3532               '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3533               'archive',
3534               '--format', 'tar.bz2',
3535               '--prefix', distdir + '/',
3536               '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3537               pg_git_revision],
3538     output: distdir + '.tar.bz2',
3539   )
3540 else
3541   tar_bz2 = custom_target('tar.bz2',
3542     command: [perl, '-e', 'exit 1'],
3543     output: distdir + '.tar.bz2',
3544   )
3545 endif
3547 alias_target('pgdist', [tar_gz, tar_bz2])
3549 # Make the standard "dist" command fail, to prevent accidental use.
3550 # But not if we are in a subproject, in case the parent project wants to
3551 # create a dist using the standard Meson command.
3552 if not meson.is_subproject()
3553   # We can only pass the identifier perl here when we depend on >= 0.55
3554   if meson.version().version_compare('>=0.55')
3555     meson.add_dist_script(perl, '-e', 'exit 1')
3556   endif
3557 endif
3561 ###############################################################
3562 # The End, The End, My Friend
3563 ###############################################################
3565 if meson.version().version_compare('>=0.57')
3567   summary(
3568     {
3569       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3570       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3571       'segment size': get_option('segsize_blocks') != 0 ?
3572         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3573         '@0@ GB'.format(get_option('segsize')),
3574     },
3575     section: 'Data layout',
3576   )
3578   summary(
3579     {
3580       'host system': '@0@ @1@'.format(host_system, host_cpu),
3581       'build system': '@0@ @1@'.format(build_machine.system(),
3582                                        build_machine.cpu_family()),
3583     },
3584     section: 'System',
3585   )
3587   summary(
3588     {
3589       'linker': '@0@'.format(cc.get_linker_id()),
3590       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3591     },
3592     section: 'Compiler',
3593   )
3595   summary(
3596     {
3597       'CPP FLAGS': ' '.join(cppflags),
3598       'C FLAGS, functional': ' '.join(cflags),
3599       'C FLAGS, warnings': ' '.join(cflags_warn),
3600       'C FLAGS, modules': ' '.join(cflags_mod),
3601       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3602       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3603     },
3604     section: 'Compiler Flags',
3605   )
3607   if llvm.found()
3608     summary(
3609       {
3610         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3611       },
3612       section: 'Compiler',
3613     )
3615     summary(
3616       {
3617         'C++ FLAGS, functional': ' '.join(cxxflags),
3618         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3619         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3620       },
3621       section: 'Compiler Flags',
3622     )
3623   endif
3625   summary(
3626     {
3627       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3628       'dtrace': dtrace,
3629       'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3630     },
3631     section: 'Programs',
3632   )
3634   summary(
3635     {
3636       'bonjour': bonjour,
3637       'bsd_auth': bsd_auth,
3638       'docs': docs_dep,
3639       'docs_pdf': docs_pdf_dep,
3640       'gss': gssapi,
3641       'icu': icu,
3642       'ldap': ldap,
3643       'libxml': libxml,
3644       'libxslt': libxslt,
3645       'llvm': llvm,
3646       'lz4': lz4,
3647       'nls': libintl,
3648       'openssl': ssl,
3649       'pam': pam,
3650       'plperl': perl_dep,
3651       'plpython': python3_dep,
3652       'pltcl': tcl_dep,
3653       'readline': readline,
3654       'selinux': selinux,
3655       'systemd': systemd,
3656       'uuid': uuid,
3657       'zlib': zlib,
3658       'zstd': zstd,
3659     },
3660     section: 'External libraries',
3661   )
3663 endif