Doc: list AT TIME ZONE and COLLATE in operator precedence table.
[pgsql.git] / meson.build
blob51b5285924ab7390f569462dbe69bf7bfe5465a4
1 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
3 # Entry point for building PostgreSQL with meson
5 # Good starting points for writing meson.build files are:
6 #  - https://mesonbuild.com/Syntax.html
7 #  - https://mesonbuild.com/Reference-manual.html
9 project('postgresql',
10   ['c'],
11   version: '16.1',
12   license: 'PostgreSQL',
14   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
15   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
16   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
17   meson_version: '>=0.54',
18   default_options: [
19     'warning_level=1', #-Wall equivalent
20     'b_pch=false',
21     'buildtype=debugoptimized', # -O2 + debug
22     # For compatibility with the autoconf build, set a default prefix. This
23     # works even on windows, where it's a drive-relative path (i.e. when on
24     # d:/somepath it'll install to d:/usr/local/pgsql)
25     'prefix=/usr/local/pgsql',
26   ]
31 ###############################################################
32 # Basic prep
33 ###############################################################
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
42 cc = meson.get_compiler('c')
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
46 auto_features = get_option('auto_features')
50 ###############################################################
51 # Safety first
52 ###############################################################
54 # It's very easy to get into confusing states when the source directory
55 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
56 # refuse to build in that case.
58 # There's a more elaborate check later, that checks for conflicts around all
59 # generated files. But we can only do that much further down the line, so this
60 # quick check seems worth it. Adhering to this advice should clean up the
61 # conflict, but won't protect against somebody doing make distclean or just
62 # removing pg_config.h
63 errmsg_nonclean_base = '''
64 ****
65 Non-clean source code directory detected.
67 To build with meson the source tree may not have an in-place, ./configure
68 style, build configured. You can have both meson and ./configure style builds
69 for the same source tree by building out-of-source / VPATH with
70 configure. Alternatively use a separate check out for meson based builds.
72 @0@
73 ****'''
74 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
75   errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
76   error(errmsg_nonclean_base.format(errmsg_cleanup))
77 endif
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
88 postgres_lib_d = get_option('extra_lib_dirs')
90 cppflags = []
92 cflags = []
93 cxxflags = []
94 cflags_warn = []
95 cxxflags_warn = []
96 cflags_mod = []
97 cxxflags_mod = []
99 ldflags = []
100 ldflags_be = []
101 ldflags_sl = []
102 ldflags_mod = []
104 test_c_args = []
106 os_deps = []
107 backend_both_deps = []
108 backend_deps = []
109 libpq_deps = []
111 pg_sysroot = ''
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
122 pg_version = meson.project_version()
124 if pg_version.endswith('devel')
125   pg_version_arr = [pg_version.split('devel')[0], '0']
126 elif pg_version.contains('beta')
127   pg_version_arr = [pg_version.split('beta')[0], '0']
128 elif pg_version.contains('rc')
129   pg_version_arr = [pg_version.split('rc')[0], '0']
130 else
131   pg_version_arr = pg_version.split('.')
132 endif
134 pg_version_major = pg_version_arr[0].to_int()
135 pg_version_minor = pg_version_arr[1].to_int()
136 pg_version_num = (pg_version_major * 10000) + pg_version_minor
138 pg_url = 'https://www.postgresql.org/'
140 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
141 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
142 cdata.set_quoted('PACKAGE_URL', pg_url)
143 cdata.set_quoted('PACKAGE_VERSION', pg_version)
144 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
145 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
147 pg_version += get_option('extra_version')
148 cdata.set_quoted('PG_VERSION', pg_version)
149 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
150 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
151 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
152 cdata.set('PG_VERSION_NUM', pg_version_num)
153 # PG_VERSION_STR is built later, it depends on compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 # meson's system names don't quite map to our "traditional" names. In some
163 # places we need the "traditional" name, e.g., for mapping
164 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
165 # that purpose.
166 portname = host_system
168 exesuffix = '' # overridden below where necessary
169 dlsuffix = '.so' # overridden below where necessary
170 library_path_var = 'LD_LIBRARY_PATH'
172 # Format of file to control exports from libraries, and how to pass them to
173 # the compiler. For export_fmt @0@ is the path to the file export file.
174 export_file_format = 'gnu'
175 export_file_suffix = 'list'
176 export_fmt = '-Wl,--version-script=@0@'
178 # Flags to add when linking a postgres extension, @0@ is path to
179 # the relevant object on the platform.
180 mod_link_args_fmt = []
182 memset_loop_limit = 1024
184 # Choice of shared memory and semaphore implementation
185 shmem_kind = 'sysv'
186 sema_kind = 'sysv'
188 # We implement support for some operating systems by pretending they're
189 # another. Map here, before determining system properties below
190 if host_system == 'dragonfly'
191   # apparently the most similar
192   host_system = 'netbsd'
193 endif
195 if host_system == 'aix'
196   library_path_var = 'LIBPATH'
198   export_file_format = 'aix'
199   export_fmt = '-Wl,-bE:@0@'
200   mod_link_args_fmt = ['-Wl,-bI:@0@']
201   mod_link_with_dir = 'libdir'
202   mod_link_with_name = '@0@.imp'
204   # M:SRE sets a flag indicating that an object is a shared library. Seems to
205   # work in some circumstances without, but required in others.
206   ldflags_sl += '-Wl,-bM:SRE'
207   ldflags_be += '-Wl,-brtllib'
209   # Native memset() is faster, tested on:
210   # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
211   # - AIX 5.3 ML3, gcc 4.0.1
212   memset_loop_limit = 0
214 elif host_system == 'cygwin'
215   sema_kind = 'unnamed_posix'
216   cppflags += '-D_GNU_SOURCE'
217   dlsuffix = '.dll'
218   mod_link_args_fmt = ['@0@']
219   mod_link_with_name = 'lib@0@.exe.a'
220   mod_link_with_dir = 'libdir'
222 elif host_system == 'darwin'
223   dlsuffix = '.dylib'
224   library_path_var = 'DYLD_LIBRARY_PATH'
226   export_file_format = 'darwin'
227   export_fmt = '-Wl,-exported_symbols_list,@0@'
229   mod_link_args_fmt = ['-bundle_loader', '@0@']
230   mod_link_with_dir = 'bindir'
231   mod_link_with_name = '@0@'
233   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
234   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
235   message('darwin sysroot: @0@'.format(pg_sysroot))
236   if pg_sysroot != ''
237     cflags += ['-isysroot', pg_sysroot]
238     ldflags += ['-isysroot', pg_sysroot]
239   endif
240   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
241   # don't want because a) it's different from what we do for autoconf, b) it
242   # causes warnings starting in macOS Ventura
243   ldflags_mod += ['-Wl,-undefined,error']
245 elif host_system == 'freebsd'
246   sema_kind = 'unnamed_posix'
248 elif host_system == 'linux'
249   sema_kind = 'unnamed_posix'
250   cppflags += '-D_GNU_SOURCE'
252 elif host_system == 'netbsd'
253   # We must resolve all dynamic linking in the core server at program start.
254   # Otherwise the postmaster can self-deadlock due to signals interrupting
255   # resolution of calls, since NetBSD's linker takes a lock while doing that
256   # and some postmaster signal handlers do things that will also acquire that
257   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
258   # While there's not a hard reason to adopt these settings for our other
259   # executables, there's also little reason not to, so just add them to
260   # LDFLAGS.
261   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
263 elif host_system == 'openbsd'
264   # you're ok
266 elif host_system == 'sunos'
267   portname = 'solaris'
268   export_fmt = '-Wl,-M@0@'
269   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
271 elif host_system == 'windows'
272   portname = 'win32'
273   exesuffix = '.exe'
274   dlsuffix = '.dll'
275   library_path_var = ''
277   export_file_format = 'win'
278   export_file_suffix = 'def'
279   if cc.get_id() == 'msvc'
280     export_fmt = '/DEF:@0@'
281     mod_link_with_name = '@0@.exe.lib'
282   else
283     export_fmt = '@0@'
284     mod_link_with_name = 'lib@0@.exe.a'
285   endif
286   mod_link_args_fmt = ['@0@']
287   mod_link_with_dir = 'libdir'
289   shmem_kind = 'win32'
290   sema_kind = 'win32'
292   cdata.set('WIN32_STACK_RLIMIT', 4194304)
293   if cc.get_id() == 'msvc'
294     ldflags += '/INCREMENTAL:NO'
295     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
296     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
297   else
298     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
299     # Need to allow multiple definitions, we e.g. want to override getopt.
300     ldflags += '-Wl,--allow-multiple-definition'
301     # Ensure we get MSVC-like linking behavior.
302     ldflags += '-Wl,--disable-auto-import'
303   endif
305   os_deps += cc.find_library('ws2_32', required: true)
306   secur32_dep = cc.find_library('secur32', required: true)
307   backend_deps += secur32_dep
308   libpq_deps += secur32_dep
310   postgres_inc_d += 'src/include/port/win32'
311   if cc.get_id() == 'msvc'
312     postgres_inc_d += 'src/include/port/win32_msvc'
313   endif
315   windows = import('windows')
317 else
318   # XXX: Should we add an option to override the host_system as an escape
319   # hatch?
320   error('unknown host system: @0@'.format(host_system))
321 endif
325 ###############################################################
326 # Program paths
327 ###############################################################
329 # External programs
330 perl = find_program(get_option('PERL'), required: true, native: true)
331 python = find_program(get_option('PYTHON'), required: true, native: true)
332 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
333 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
334 sed = find_program(get_option('SED'), 'sed', native: true)
335 prove = find_program(get_option('PROVE'), native: true, required: false)
336 tar = find_program(get_option('TAR'), native: true)
337 gzip = find_program(get_option('GZIP'), native: true)
338 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
339 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
340 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
341 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
342 missing = find_program('config/missing', native: true)
343 cp = find_program('cp', required: false, native: true)
344 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
345 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
347 bison_flags = []
348 if bison.found()
349   bison_version_c = run_command(bison, '--version', check: true)
350   # bison version string helpfully is something like
351   # >>bison (GNU bison) 3.8.1<<
352   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
353   if bison_version.version_compare('>=3.0')
354     bison_flags += ['-Wno-deprecated']
355   endif
356 endif
357 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
358 bison_kw = {
359   'output': ['@BASENAME@.c', '@BASENAME@.h'],
360   'command': bison_cmd,
363 flex_flags = []
364 flex_wrapper = files('src/tools/pgflex')
365 flex_cmd = [python, flex_wrapper,
366   '--builddir', '@BUILD_ROOT@',
367   '--srcdir', '@SOURCE_ROOT@',
368   '--privatedir', '@PRIVATE_DIR@',
369   '--flex', flex, '--perl', perl,
370   '-i', '@INPUT@', '-o', '@OUTPUT0@',
373 wget = find_program('wget', required: false, native: true)
374 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
376 install_files = files('src/tools/install_files')
380 ###############################################################
381 # Path to meson (for tests etc)
382 ###############################################################
384 # NB: this should really be part of meson, see
385 # https://github.com/mesonbuild/meson/issues/8511
386 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
388 if meson_binpath_r.stdout() == ''
389   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
390     meson_binpath_r.returncode(),
391     meson_binpath_r.stdout(),
392     meson_binpath_r.stderr()))
393 endif
395 meson_binpath_s = meson_binpath_r.stdout().split('\n')
396 meson_binpath_len = meson_binpath_s.length()
398 if meson_binpath_len < 1
399   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
400 endif
402 i = 0
403 meson_impl = ''
404 meson_binpath = ''
405 meson_args = []
406 foreach e : meson_binpath_s
407   if i == 0
408     meson_impl = e
409   elif i == 1
410     meson_binpath = e
411   else
412     meson_args += e
413   endif
414   i += 1
415 endforeach
417 if meson_impl not in ['muon', 'meson']
418   error('unknown meson implementation "@0@"'.format(meson_impl))
419 endif
421 meson_bin = find_program(meson_binpath, native: true)
425 ###############################################################
426 # Option Handling
427 ###############################################################
429 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
431 blocksize = get_option('blocksize').to_int() * 1024
433 if get_option('segsize_blocks') != 0
434   if get_option('segsize') != 1
435     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
436   endif
438   segsize = get_option('segsize_blocks')
439 else
440   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
441 endif
443 cdata.set('BLCKSZ', blocksize, description:
444 '''Size of a disk block --- this also limits the size of a tuple. You can set
445    it bigger if you need bigger tuples (although TOAST should reduce the need
446    to have large tuples, since fields can be spread across multiple tuples).
447    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
448    currently 2^15 (32768). This is determined by the 15-bit widths of the
449    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
450    Changing BLCKSZ requires an initdb.''')
452 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
453 cdata.set('RELSEG_SIZE', segsize)
454 cdata.set('DEF_PGPORT', get_option('pgport'))
455 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
456 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
457 if get_option('system_tzdata') != ''
458   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
459 endif
463 ###############################################################
464 # Directories
465 ###############################################################
467 # These are set by the equivalent --xxxdir configure options.  We
468 # append "postgresql" to some of them, if the string does not already
469 # contain "pgsql" or "postgres", in order to avoid directory clutter.
471 pkg = 'postgresql'
473 dir_prefix = get_option('prefix')
475 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
477 dir_bin = get_option('bindir')
479 dir_data = get_option('datadir')
480 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
481   dir_data = dir_data / pkg
482 endif
484 dir_sysconf = get_option('sysconfdir')
485 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
486   dir_sysconf = dir_sysconf / pkg
487 endif
489 dir_lib = get_option('libdir')
491 dir_lib_pkg = dir_lib
492 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
493   dir_lib_pkg = dir_lib_pkg / pkg
494 endif
496 dir_pgxs = dir_lib_pkg / 'pgxs'
498 dir_include = get_option('includedir')
500 dir_include_pkg = dir_include
501 dir_include_pkg_rel = ''
502 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
503   dir_include_pkg = dir_include_pkg / pkg
504   dir_include_pkg_rel = pkg
505 endif
507 dir_man = get_option('mandir')
509 # FIXME: These used to be separately configurable - worth adding?
510 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
511 dir_doc_html = dir_doc / 'html'
513 dir_locale = get_option('localedir')
516 # Derived values
517 dir_bitcode = dir_lib_pkg / 'bitcode'
518 dir_include_internal = dir_include_pkg / 'internal'
519 dir_include_server = dir_include_pkg / 'server'
520 dir_include_extension = dir_include_server / 'extension'
521 dir_data_extension = dir_data / 'extension'
525 ###############################################################
526 # Search paths, preparation for compiler tests
528 # NB: Arguments added later are not automatically used for subsequent
529 # configuration-time checks (so they are more isolated). If they should be
530 # used, they need to be added to test_c_args as well.
531 ###############################################################
533 postgres_inc = [include_directories(postgres_inc_d)]
534 test_lib_d = postgres_lib_d
535 test_c_args = cppflags + cflags
539 ###############################################################
540 # Library: bsd-auth
541 ###############################################################
543 bsd_authopt = get_option('bsd_auth')
544 bsd_auth = not_found_dep
545 if cc.check_header('bsd_auth.h', required: bsd_authopt,
546     args: test_c_args, include_directories: postgres_inc)
547   cdata.set('USE_BSD_AUTH', 1)
548   bsd_auth = declare_dependency()
549 endif
553 ###############################################################
554 # Library: bonjour
556 # For now don't search for DNSServiceRegister in a library - only Apple's
557 # Bonjour implementation, which is always linked, works.
558 ###############################################################
560 bonjouropt = get_option('bonjour')
561 bonjour = not_found_dep
562 if cc.check_header('dns_sd.h', required: bonjouropt,
563     args: test_c_args, include_directories: postgres_inc) and \
564    cc.has_function('DNSServiceRegister',
565     args: test_c_args, include_directories: postgres_inc)
566   cdata.set('USE_BONJOUR', 1)
567   bonjour = declare_dependency()
568 endif
572 ###############################################################
573 # Option: docs in HTML and man page format
574 ###############################################################
576 docs_opt = get_option('docs')
577 docs_dep = not_found_dep
578 if not docs_opt.disabled()
579   if xmllint_bin.found() and xsltproc_bin.found()
580     docs_dep = declare_dependency()
581   elif docs_opt.enabled()
582     error('missing required tools for docs in HTML / man page format')
583   endif
584 endif
588 ###############################################################
589 # Option: docs in PDF format
590 ###############################################################
592 docs_pdf_opt = get_option('docs_pdf')
593 docs_pdf_dep = not_found_dep
594 if not docs_pdf_opt.disabled()
595   fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
596   if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
597     docs_pdf_dep = declare_dependency()
598   elif docs_pdf_opt.enabled()
599     error('missing required tools for docs in PDF format')
600   endif
601 endif
605 ###############################################################
606 # Library: GSSAPI
607 ###############################################################
609 gssapiopt = get_option('gssapi')
610 krb_srvtab = ''
611 have_gssapi = false
612 if not gssapiopt.disabled()
613   gssapi = dependency('krb5-gssapi', required: gssapiopt)
614   have_gssapi = gssapi.found()
616   if not have_gssapi
617   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
618       args: test_c_args, include_directories: postgres_inc)
619     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
620   elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
621     cdata.set('HAVE_GSSAPI_H', 1)
622   else
623     have_gssapi = false
624   endif
626   if not have_gssapi
627   elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi, required: false,
628       args: test_c_args, include_directories: postgres_inc)
629     cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
630   elif cc.check_header('gssapi_ext.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
631     cdata.set('HAVE_GSSAPI_EXT_H', 1)
632   else
633     have_gssapi = false
634   endif
636   if not have_gssapi
637   elif cc.has_function('gss_store_cred_into', dependencies: gssapi,
638       args: test_c_args, include_directories: postgres_inc)
639     cdata.set('ENABLE_GSS', 1)
641     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
642     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
643   elif gssapiopt.enabled()
644     error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
645   else
646     have_gssapi = false
647   endif
648 endif
649 if not have_gssapi
650   gssapi = not_found_dep
651 endif
655 ###############################################################
656 # Library: ldap
657 ###############################################################
659 ldapopt = get_option('ldap')
660 if ldapopt.disabled()
661   ldap = not_found_dep
662   ldap_r = not_found_dep
663 elif host_system == 'windows'
664   ldap = cc.find_library('wldap32', required: ldapopt)
665   ldap_r = ldap
666 else
667   # macos framework dependency is buggy for ldap (one can argue whether it's
668   # Apple's or meson's fault), leading to an endless recursion with ldap.h
669   # including itself. See https://github.com/mesonbuild/meson/issues/10002
670   # Luckily we only need pkg-config support, so the workaround isn't
671   # complicated.
672   ldap = dependency('ldap', method: 'pkg-config', required: false)
673   ldap_r = ldap
675   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
676   # installed
677   if not ldap.found()
678     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
679       has_headers: 'ldap.h', header_include_directories: postgres_inc)
681     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
682     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
683     # library from a separate OpenLDAP installation).  The most reliable
684     # way to check that is to check for a function introduced in 2.5.
685     if not ldap.found()
686       # don't have ldap, we shouldn't check for ldap_r
687     elif cc.has_function('ldap_verify_credentials',
688         dependencies: ldap, args: test_c_args)
689       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
690     else
692       # Use ldap_r for FE if available, else assume ldap is thread-safe.
693       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
694         has_headers: 'ldap.h', header_include_directories: postgres_inc)
695       if not ldap_r.found()
696         ldap_r = ldap
697       else
698         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
699         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
700       endif
702       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
703       # process.  Check for OpenLDAP versions known not to tolerate doing so;
704       # assume non-OpenLDAP implementations are safe.  The dblink test suite
705       # exercises the hazardous interaction directly.
706       compat_test_code = '''
707 #include <ldap.h>
708 #if !defined(LDAP_VENDOR_VERSION) || \
709      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
710       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
711 choke me
712 #endif
714       if not cc.compiles(compat_test_code,
715           name: 'LDAP implementation compatible',
716           dependencies: ldap, args: test_c_args)
717         warning('''
718 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
719 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
720 *** also uses LDAP will crash on exit.''')
721       endif
722     endif
723   endif
725   if ldap.found() and cc.has_function('ldap_initialize',
726       dependencies: ldap, args: test_c_args)
727     cdata.set('HAVE_LDAP_INITIALIZE', 1)
728   endif
729 endif
731 if ldap.found()
732   assert(ldap_r.found())
733   cdata.set('USE_LDAP', 1)
734 else
735   assert(not ldap_r.found())
736 endif
740 ###############################################################
741 # Library: LLVM
742 ###############################################################
744 llvmopt = get_option('llvm')
745 llvm = not_found_dep
746 if add_languages('cpp', required: llvmopt, native: false)
747   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
749   if llvm.found()
751     cdata.set('USE_LLVM', 1)
753     cpp = meson.get_compiler('cpp')
755     llvm_binpath = llvm.get_variable(configtool: 'bindir')
757     ccache = find_program('ccache', native: true, required: false)
758     clang = find_program(llvm_binpath / 'clang', required: true)
759   endif
760 elif llvmopt.auto()
761   message('llvm requires a C++ compiler')
762 endif
766 ###############################################################
767 # Library: icu
768 ###############################################################
770 icuopt = get_option('icu')
771 if not icuopt.disabled()
772   icu = dependency('icu-uc', required: icuopt)
773   icu_i18n = dependency('icu-i18n', required: icuopt)
775   if icu.found()
776     cdata.set('USE_ICU', 1)
777   endif
779 else
780   icu = not_found_dep
781   icu_i18n = not_found_dep
782 endif
786 ###############################################################
787 # Library: libxml
788 ###############################################################
790 libxmlopt = get_option('libxml')
791 if not libxmlopt.disabled()
792   libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
794   if libxml.found()
795     cdata.set('USE_LIBXML', 1)
796   endif
797 else
798   libxml = not_found_dep
799 endif
803 ###############################################################
804 # Library: libxslt
805 ###############################################################
807 libxsltopt = get_option('libxslt')
808 if not libxsltopt.disabled()
809   libxslt = dependency('libxslt', required: libxsltopt)
811   if libxslt.found()
812     cdata.set('USE_LIBXSLT', 1)
813   endif
814 else
815   libxslt = not_found_dep
816 endif
820 ###############################################################
821 # Library: lz4
822 ###############################################################
824 lz4opt = get_option('lz4')
825 if not lz4opt.disabled()
826   lz4 = dependency('liblz4', required: lz4opt)
828   if lz4.found()
829     cdata.set('USE_LZ4', 1)
830     cdata.set('HAVE_LIBLZ4', 1)
831   endif
833 else
834   lz4 = not_found_dep
835 endif
839 ###############################################################
840 # Library: Tcl (for pltcl)
842 # NB: tclConfig.sh is used in autoconf build for getting
843 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
844 # variables. For now we have not seen a need to copy
845 # that behaviour to the meson build.
846 ###############################################################
848 tclopt = get_option('pltcl')
849 tcl_version = get_option('tcl_version')
850 tcl_dep = not_found_dep
851 if not tclopt.disabled()
853   # via pkg-config
854   tcl_dep = dependency(tcl_version, required: false)
856   if not tcl_dep.found()
857     tcl_dep = cc.find_library(tcl_version,
858       required: tclopt,
859       dirs: test_lib_d)
860   endif
862   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
863     tcl_dep = not_found_dep
864   endif
865 endif
869 ###############################################################
870 # Library: pam
871 ###############################################################
873 pamopt = get_option('pam')
874 if not pamopt.disabled()
875   pam = dependency('pam', required: false)
877   if not pam.found()
878     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
879   endif
881   if pam.found()
882     pam_header_found = false
884     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
885     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
886         args: test_c_args, include_directories: postgres_inc)
887       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
888       pam_header_found = true
889     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
890         args: test_c_args, include_directories: postgres_inc)
891       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
892       pam_header_found = true
893     endif
895     if pam_header_found
896       cdata.set('USE_PAM', 1)
897     else
898       pam = not_found_dep
899     endif
900   endif
901 else
902   pam = not_found_dep
903 endif
907 ###############################################################
908 # Library: Perl (for plperl)
909 ###############################################################
911 perlopt = get_option('plperl')
912 perl_dep = not_found_dep
913 if not perlopt.disabled()
914   perl_may_work = true
916   # First verify that perl has the necessary dependencies installed
917   perl_mods = run_command(
918     [perl,
919      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
920      '-e', ''],
921     check: false)
922   if perl_mods.returncode() != 0
923     perl_may_work = false
924     perl_msg = 'perl installation does not have the required modules'
925   endif
927   # Then inquire perl about its configuration
928   if perl_may_work
929     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
930     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
931     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
932     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
933     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
935     perl_inc_dir = '@0@/CORE'.format(archlibexp)
937     if perlversion.version_compare('< 5.14')
938       perl_may_work = false
939       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
940     elif useshrplib != 'true'
941       perl_may_work = false
942       perl_msg = 'need a shared perl'
943     endif
944   endif
946   if perl_may_work
947     # On most platforms, archlibexp is also where the Perl include files live ...
948     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
949     # ... but on newer macOS versions, we must use -iwithsysroot to look
950     # under sysroot
951     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
952        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
953       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
954     endif
956     # check compiler finds header
957     if not cc.has_header('perl.h', required: false,
958         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
959       perl_may_work = false
960       perl_msg = 'missing perl.h'
961     endif
962   endif
964   if perl_may_work
965     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
967     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
968     foreach flag : perl_ccflags_r.split(' ')
969       if flag.startswith('-D') and \
970           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
971         perl_ccflags += flag
972       endif
973     endforeach
975     if host_system == 'windows'
976       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
978       if cc.get_id() == 'msvc'
979         # prevent binary mismatch between MSVC built plperl and Strawberry or
980         # msys ucrt perl libraries
981         perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
982       endif
983     endif
985     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
986     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
988     # We are after Embed's ldopts, but without the subset mentioned in
989     # Config's ccdlflags and ldflags.  (Those are the choices of those who
990     # built the Perl installation, which are not necessarily appropriate
991     # for building PostgreSQL.)
992     ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
993     undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
994     undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
996     perl_ldopts = []
997     foreach ldopt : ldopts.split(' ')
998       if ldopt == '' or ldopt in undesired
999         continue
1000       endif
1002       perl_ldopts += ldopt.strip('"')
1003     endforeach
1005     message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
1006     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1008     perl_dep_int = declare_dependency(
1009       compile_args: perl_ccflags,
1010       link_args: perl_ldopts,
1011       version: perlversion,
1012     )
1014     # While we're at it, check that we can link to libperl.
1015     # On most platforms, if perl.h is there then libperl.so will be too, but
1016     # at this writing Debian packages them separately.
1017     perl_link_test = '''
1018 /* see plperl.h */
1019 #ifdef _MSC_VER
1020 #define __inline__ inline
1021 #endif
1022 #include <EXTERN.h>
1023 #include <perl.h>
1024 int main(void)
1026 perl_alloc();
1027 }'''
1028     if not cc.links(perl_link_test, name: 'libperl',
1029           args: test_c_args + perl_ccflags + perl_ldopts,
1030           include_directories: postgres_inc)
1031       perl_may_work = false
1032       perl_msg = 'missing libperl'
1033     endif
1035   endif # perl_may_work
1037   if perl_may_work
1038     perl_dep = perl_dep_int
1039   else
1040     if perlopt.enabled()
1041       error('dependency plperl failed: @0@'.format(perl_msg))
1042     else
1043       message('disabling optional dependency plperl: @0@'.format(perl_msg))
1044     endif
1045   endif
1046 endif
1050 ###############################################################
1051 # Library: Python (for plpython)
1052 ###############################################################
1054 pyopt = get_option('plpython')
1055 python3_dep = not_found_dep
1056 if not pyopt.disabled()
1057   pm = import('python')
1058   python3_inst = pm.find_installation(required: pyopt)
1059   if python3_inst.found()
1060     python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1061     # Remove this check after we depend on Meson >= 1.1.0
1062     if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt)
1063       python3_dep = not_found_dep
1064     endif
1065   endif
1066 endif
1070 ###############################################################
1071 # Library: Readline
1072 ###############################################################
1074 if not get_option('readline').disabled()
1075   libedit_preferred = get_option('libedit_preferred')
1076   # Set the order of readline dependencies
1077   check_readline_deps = libedit_preferred ? \
1078     ['libedit', 'readline'] : ['readline', 'libedit']
1080   foreach readline_dep : check_readline_deps
1081     readline = dependency(readline_dep, required: false)
1082     if not readline.found()
1083       readline = cc.find_library(readline_dep,
1084         required: get_option('readline'),
1085         dirs: test_lib_d)
1086     endif
1087     if readline.found()
1088       break
1089     endif
1090   endforeach
1092   if readline.found()
1093     cdata.set('HAVE_LIBREADLINE', 1)
1095     editline_prefix = {
1096       'header_prefix': 'editline/',
1097       'flag_prefix': 'EDITLINE_',
1098     }
1099     readline_prefix = {
1100       'header_prefix': 'readline/',
1101       'flag_prefix': 'READLINE_',
1102     }
1103     default_prefix = {
1104       'header_prefix': '',
1105       'flag_prefix': '',
1106     }
1108     # Set the order of prefixes
1109     prefixes = libedit_preferred ? \
1110       [editline_prefix, default_prefix, readline_prefix] : \
1111       [readline_prefix, default_prefix, editline_prefix]
1113     at_least_one_header_found = false
1114     foreach header : ['history', 'readline']
1115       is_found = false
1116       foreach prefix : prefixes
1117         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1118         # Check history.h and readline.h
1119         if not is_found and cc.has_header(header_file,
1120             args: test_c_args, include_directories: postgres_inc,
1121             dependencies: [readline], required: false)
1122           if header == 'readline'
1123             readline_h = header_file
1124           endif
1125           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1126           is_found = true
1127           at_least_one_header_found = true
1128         endif
1129       endforeach
1130     endforeach
1132     if not at_least_one_header_found
1133       error('''readline header not found
1134 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1135 failure. It is possible the compiler isn't looking in the proper directory.
1136 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1137     endif
1139     check_funcs = [
1140       'append_history',
1141       'history_truncate_file',
1142       'rl_completion_matches',
1143       'rl_filename_completion_function',
1144       'rl_reset_screen_size',
1145       'rl_variable_bind',
1146     ]
1148     foreach func : check_funcs
1149       found = cc.has_function(func, dependencies: [readline],
1150         args: test_c_args, include_directories: postgres_inc)
1151       cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1152     endforeach
1154     check_vars = [
1155       'rl_completion_suppress_quote',
1156       'rl_filename_quote_characters',
1157       'rl_filename_quoting_function',
1158     ]
1160     foreach var : check_vars
1161       cdata.set('HAVE_' + var.to_upper(),
1162         cc.has_header_symbol(readline_h, var,
1163           args: test_c_args, include_directories: postgres_inc,
1164           prefix: '#include <stdio.h>',
1165           dependencies: [readline]) ? 1 : false)
1166     endforeach
1168     # If found via cc.find_library() ensure headers are found when using the
1169     # dependency. On meson < 0.57 one cannot do compiler checks using the
1170     # dependency returned by declare_dependency(), so we can't do this above.
1171     if readline.type_name() == 'library'
1172       readline = declare_dependency(dependencies: readline,
1173         include_directories: postgres_inc)
1174     endif
1176     # On windows with mingw readline requires auto-import to successfully
1177     # link, as the headers don't use declspec(dllimport)
1178     if host_system == 'windows' and cc.get_id() != 'msvc'
1179       readline = declare_dependency(dependencies: readline,
1180         link_args: '-Wl,--enable-auto-import')
1181     endif
1182   endif
1184   # XXX: Figure out whether to implement mingw warning equivalent
1185 else
1186   readline = not_found_dep
1187 endif
1191 ###############################################################
1192 # Library: selinux
1193 ###############################################################
1195 selinux = not_found_dep
1196 selinuxopt = get_option('selinux')
1197 if meson.version().version_compare('>=0.59')
1198   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1199 endif
1200 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1201 cdata.set('HAVE_LIBSELINUX',
1202   selinux.found() ? 1 : false)
1206 ###############################################################
1207 # Library: systemd
1208 ###############################################################
1210 systemd = not_found_dep
1211 systemdopt = get_option('systemd')
1212 if meson.version().version_compare('>=0.59')
1213   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1214 endif
1215 systemd = dependency('libsystemd', required: systemdopt)
1216 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1220 ###############################################################
1221 # Library: SSL
1222 ###############################################################
1224 ssl = not_found_dep
1225 ssl_library = 'none'
1226 sslopt = get_option('ssl')
1228 if sslopt == 'auto' and auto_features.disabled()
1229   sslopt = 'none'
1230 endif
1232 if sslopt in ['auto', 'openssl']
1233   openssl_required = (sslopt == 'openssl')
1235   # Try to find openssl via pkg-config et al, if that doesn't work
1236   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1237   # the library names that we know about.
1239   # via pkg-config et al
1240   ssl = dependency('openssl', required: false)
1241   # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1242   # we pass cc.find_library() results if necessary
1243   ssl_int = []
1245   # via library + headers
1246   if not ssl.found()
1247     ssl_lib = cc.find_library('ssl',
1248       dirs: test_lib_d,
1249       header_include_directories: postgres_inc,
1250       has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1251       required: openssl_required)
1252     crypto_lib = cc.find_library('crypto',
1253       dirs: test_lib_d,
1254       required: openssl_required)
1255     if ssl_lib.found() and crypto_lib.found()
1256       ssl_int = [ssl_lib, crypto_lib]
1257       ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1258     endif
1259   elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1260        cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1261     ssl_int = [ssl]
1262   else
1263     ssl = not_found_dep
1264   endif
1266   if ssl.found()
1267     check_funcs = [
1268       ['CRYPTO_new_ex_data', {'required': true}],
1269       ['SSL_new', {'required': true}],
1271       # Functions introduced in OpenSSL 1.0.2.
1272       ['X509_get_signature_nid'],
1273       ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1275       # Functions introduced in OpenSSL 1.1.0. We used to check for
1276       # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1277       # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1278       # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1279       # functions.
1280       ['OPENSSL_init_ssl'],
1281       ['BIO_get_data'],
1282       ['BIO_meth_new'],
1283       ['ASN1_STRING_get0_data'],
1284       ['HMAC_CTX_new'],
1285       ['HMAC_CTX_free'],
1287       # OpenSSL versions before 1.1.0 required setting callback functions, for
1288       # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1289       # function was removed.
1290       ['CRYPTO_lock'],
1292       # Function introduced in OpenSSL 1.1.1
1293       ['X509_get_signature_info'],
1294     ]
1296     are_openssl_funcs_complete = true
1297     foreach c : check_funcs
1298       func = c.get(0)
1299       val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1300       required = c.get(1, {}).get('required', false)
1301       if required and not val
1302         are_openssl_funcs_complete = false
1303         if openssl_required
1304           error('openssl function @0@ is required'.format(func))
1305         endif
1306         break
1307       elif not required
1308         cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1309       endif
1310     endforeach
1312     if are_openssl_funcs_complete
1313       cdata.set('USE_OPENSSL', 1,
1314                 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1315       cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1316                 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1317       ssl_library = 'openssl'
1318     else
1319       ssl = not_found_dep
1320     endif
1321   endif
1322 endif
1324 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1325   error('no SSL library found')
1326 endif
1330 ###############################################################
1331 # Library: uuid
1332 ###############################################################
1334 uuidopt = get_option('uuid')
1335 if uuidopt != 'none'
1336   uuidname = uuidopt.to_upper()
1337   if uuidopt == 'e2fs'
1338     uuid = dependency('uuid', required: true)
1339     uuidfunc = 'uuid_generate'
1340     uuidheader = 'uuid/uuid.h'
1341   elif uuidopt == 'bsd'
1342     # libc should have uuid function
1343     uuid = declare_dependency()
1344     uuidfunc = 'uuid_to_string'
1345     uuidheader = 'uuid.h'
1346   elif uuidopt == 'ossp'
1347     uuid = dependency('ossp-uuid', required: true)
1348     uuidfunc = 'uuid_export'
1349     uuidheader = 'uuid.h'
1350   else
1351     error('unknown uuid build option value: @0@'.format(uuidopt))
1352   endif
1354   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1355     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1356   endif
1357   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1359   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1360            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1361 else
1362   uuid = not_found_dep
1363 endif
1367 ###############################################################
1368 # Library: zlib
1369 ###############################################################
1371 zlibopt = get_option('zlib')
1372 zlib = not_found_dep
1373 if not zlibopt.disabled()
1374   zlib_t = dependency('zlib', required: zlibopt)
1376   if zlib_t.type_name() == 'internal'
1377     # if fallback was used, we don't need to test if headers are present (they
1378     # aren't built yet, so we can't test)
1379     zlib = zlib_t
1380   elif not zlib_t.found()
1381     warning('did not find zlib')
1382   elif not cc.has_header('zlib.h',
1383       args: test_c_args, include_directories: postgres_inc,
1384       dependencies: [zlib_t], required: zlibopt)
1385     warning('zlib header not found')
1386   elif not cc.has_type('z_streamp',
1387       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1388       args: test_c_args, include_directories: postgres_inc)
1389     if zlibopt.enabled()
1390       error('zlib version is too old')
1391     else
1392       warning('zlib version is too old')
1393     endif
1394   else
1395     zlib = zlib_t
1396   endif
1398   if zlib.found()
1399     cdata.set('HAVE_LIBZ', 1)
1400   endif
1401 endif
1405 ###############################################################
1406 # Library: tap test dependencies
1407 ###############################################################
1409 # Check whether tap tests are enabled or not
1410 tap_tests_enabled = false
1411 tapopt = get_option('tap_tests')
1412 if not tapopt.disabled()
1413   # Checking for perl modules for tap tests
1414   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1415   if perl_ipc_run_check.returncode() != 0
1416     message(perl_ipc_run_check.stderr().strip())
1417     if tapopt.enabled()
1418       error('Additional Perl modules are required to run TAP tests.')
1419     else
1420       warning('Additional Perl modules are required to run TAP tests.')
1421     endif
1422   else
1423     tap_tests_enabled = true
1424   endif
1425 endif
1429 ###############################################################
1430 # Library: zstd
1431 ###############################################################
1433 zstdopt = get_option('zstd')
1434 if not zstdopt.disabled()
1435   zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1437   if zstd.found()
1438     cdata.set('USE_ZSTD', 1)
1439     cdata.set('HAVE_LIBZSTD', 1)
1440   endif
1442 else
1443   zstd = not_found_dep
1444 endif
1448 ###############################################################
1449 # Compiler tests
1450 ###############################################################
1452 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1453 # unnecessarily, because we optionally rely on newer features.
1454 c99_test = '''
1455 #include <stdbool.h>
1456 #include <complex.h>
1457 #include <tgmath.h>
1458 #include <inttypes.h>
1460 struct named_init_test {
1461   int a;
1462   int b;
1465 extern void structfunc(struct named_init_test);
1467 int main(int argc, char **argv)
1469   struct named_init_test nit = {
1470     .a = 3,
1471     .b = 5,
1472   };
1474   for (int loop_var = 0; loop_var < 3; loop_var++)
1475   {
1476     nit.a += nit.b;
1477   }
1479   structfunc((struct named_init_test){1, 0});
1481   return nit.a != 0;
1485 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1486   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1487         args: test_c_args + ['-std=c99'])
1488     test_c_args += '-std=c99'
1489     cflags += '-std=c99'
1490   else
1491     error('C compiler does not support C99')
1492   endif
1493 endif
1495 sizeof_long = cc.sizeof('long', args: test_c_args)
1496 cdata.set('SIZEOF_LONG', sizeof_long)
1497 if sizeof_long == 8
1498   cdata.set('HAVE_LONG_INT_64', 1)
1499   cdata.set('PG_INT64_TYPE', 'long int')
1500   cdata.set_quoted('INT64_MODIFIER', 'l')
1501 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1502   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1503   cdata.set('PG_INT64_TYPE', 'long long int')
1504   cdata.set_quoted('INT64_MODIFIER', 'll')
1505 else
1506   error('do not know how to get a 64bit int')
1507 endif
1509 if host_machine.endian() == 'big'
1510   cdata.set('WORDS_BIGENDIAN', 1)
1511 endif
1513 alignof_types = ['short', 'int', 'long', 'double']
1514 maxalign = 0
1515 foreach t : alignof_types
1516   align = cc.alignment(t, args: test_c_args)
1517   if maxalign < align
1518     maxalign = align
1519   endif
1520   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1521 endforeach
1522 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1524 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1525 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1528 # Check if __int128 is a working 128 bit integer type, and if so
1529 # define PG_INT128_TYPE to that typename.
1531 # This currently only detects a GCC/clang extension, but support for other
1532 # environments may be added in the future.
1534 # For the moment we only test for support for 128bit math; support for
1535 # 128bit literals and snprintf is not required.
1536 if cc.links('''
1537   /*
1538    * We don't actually run this test, just link it to verify that any support
1539    * functions needed for __int128 are present.
1540    *
1541    * These are globals to discourage the compiler from folding all the
1542    * arithmetic tests down to compile-time constants.  We do not have
1543    * convenient support for 128bit literals at this point...
1544    */
1545   __int128 a = 48828125;
1546   __int128 b = 97656250;
1548   int main(void)
1549   {
1550       __int128 c,d;
1551       a = (a << 12) + 1; /* 200000000001 */
1552       b = (b << 12) + 5; /* 400000000005 */
1553       /* try the most relevant arithmetic ops */
1554       c = a * b;
1555       d = (c + b) / b;
1556       /* must use the results, else compiler may optimize arithmetic away */
1557       return d != a+1;
1558   }''',
1559   name: '__int128',
1560   args: test_c_args)
1562   buggy_int128 = false
1564   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1565   # If not cross-compiling, we can test for bugs and disable use of __int128
1566   # with buggy compilers.  If cross-compiling, hope for the best.
1567   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1568   if not meson.is_cross_build()
1569     r = cc.run('''
1570     /* This must match the corresponding code in c.h: */
1571     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1572     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1573     #elif defined(_MSC_VER)
1574     #define pg_attribute_aligned(a) __declspec(align(a))
1575     #endif
1576     typedef __int128 int128a
1577     #if defined(pg_attribute_aligned)
1578     pg_attribute_aligned(8)
1579     #endif
1580     ;
1582     int128a holder;
1583     void pass_by_val(void *buffer, int128a par) { holder = par; }
1585     int main(void)
1586     {
1587         long int i64 = 97656225L << 12;
1588         int128a q;
1589         pass_by_val(main, (int128a) i64);
1590         q = (int128a) i64;
1591         return q != holder;
1592     }''',
1593     name: '__int128 alignment bug',
1594     args: test_c_args)
1595     assert(r.compiled())
1596     if r.returncode() != 0
1597       buggy_int128 = true
1598       message('__int128 support present but buggy and thus disabled')
1599     endif
1600   endif
1602   if not buggy_int128
1603     cdata.set('PG_INT128_TYPE', '__int128')
1604     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1605   endif
1606 endif
1609 # Check if the C compiler knows computed gotos (gcc extension, also
1610 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1612 # Checking whether computed gotos are supported syntax-wise ought to
1613 # be enough, as the syntax is otherwise illegal.
1614 if cc.compiles('''
1615     static inline int foo(void)
1616     {
1617       void *labeladdrs[] = {&&my_label};
1618       goto *labeladdrs[0];
1619       my_label:
1620       return 1;
1621     }''',
1622     args: test_c_args)
1623   cdata.set('HAVE_COMPUTED_GOTO', 1)
1624 endif
1627 # Check if the C compiler understands _Static_assert(),
1628 # and define HAVE__STATIC_ASSERT if so.
1630 # We actually check the syntax ({ _Static_assert(...) }), because we need
1631 # gcc-style compound expressions to be able to wrap the thing into macros.
1632 if cc.compiles('''
1633     int main(int arg, char **argv)
1634     {
1635         ({ _Static_assert(1, "foo"); });
1636     }
1637     ''',
1638     args: test_c_args)
1639   cdata.set('HAVE__STATIC_ASSERT', 1)
1640 endif
1643 # We use <stdbool.h> if we have it and it declares type bool as having
1644 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1645 if cc.has_type('_Bool', args: test_c_args) \
1646     and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1647     and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1648   cdata.set('HAVE__BOOL', 1)
1649   cdata.set('PG_USE_STDBOOL', 1)
1650 endif
1653 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1654 # warning for each use of %m.
1655 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1656 testsrc = '''
1657 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1658 static void call_log(void)
1660     emit_log(0, "error: %s: %m", "foo");
1663 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1664 foreach a : printf_attributes
1665   if cc.compiles(testsrc.format(a),
1666       args: test_c_args + attrib_error_args, name: 'format ' + a)
1667     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1668     break
1669   endif
1670 endforeach
1673 if cc.has_function_attribute('visibility:default') and \
1674     cc.has_function_attribute('visibility:hidden')
1675   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1677   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1678   # inlineshidden to C code as well... And either way, we want to put these
1679   # flags into exported files (pgxs, .pc files).
1680   cflags_mod += '-fvisibility=hidden'
1681   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1682   ldflags_mod += '-fvisibility=hidden'
1683 endif
1686 # Check if various builtins exist. Some builtins are tested separately,
1687 # because we want to test something more complicated than the generic case.
1688 builtins = [
1689   'bswap16',
1690   'bswap32',
1691   'bswap64',
1692   'clz',
1693   'ctz',
1694   'constant_p',
1695   'frame_address',
1696   'popcount',
1697   'unreachable',
1700 foreach builtin : builtins
1701   fname = '__builtin_@0@'.format(builtin)
1702   if cc.has_function(fname, args: test_c_args)
1703     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1704   endif
1705 endforeach
1708 # Check if the C compiler understands __builtin_types_compatible_p,
1709 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1711 # We check usage with __typeof__, though it's unlikely any compiler would
1712 # have the former and not the latter.
1713 if cc.compiles('''
1714     static int x;
1715     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1716     ''',
1717     name: '__builtin_types_compatible_p',
1718     args: test_c_args)
1719   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1720 endif
1723 # Check if the C compiler understands __builtin_$op_overflow(),
1724 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1726 # Check for the most complicated case, 64 bit multiplication, as a
1727 # proxy for all of the operations.  To detect the case where the compiler
1728 # knows the function but library support is missing, we must link not just
1729 # compile, and store the results in global variables so the compiler doesn't
1730 # optimize away the call.
1731 if cc.links('''
1732     INT64 a = 1;
1733     INT64 b = 1;
1734     INT64 result;
1736     int main(void)
1737     {
1738         return __builtin_mul_overflow(a, b, &result);
1739     }''',
1740     name: '__builtin_mul_overflow',
1741     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1742     )
1743   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1744 endif
1747 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1748 # here. To prevent problems due to two detection methods working, stop
1749 # checking after one.
1750 if cc.links('''
1751     #include <cpuid.h>
1752     int main(int arg, char **argv)
1753     {
1754         unsigned int exx[4] = {0, 0, 0, 0};
1755         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1756     }
1757     ''', name: '__get_cpuid',
1758     args: test_c_args)
1759   cdata.set('HAVE__GET_CPUID', 1)
1760 elif cc.links('''
1761     #include <intrin.h>
1762     int main(int arg, char **argv)
1763     {
1764         unsigned int exx[4] = {0, 0, 0, 0};
1765         __cpuid(exx, 1);
1766     }
1767     ''', name: '__cpuid',
1768     args: test_c_args)
1769   cdata.set('HAVE__CPUID', 1)
1770 endif
1773 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1774 # versions of clang do not understand -fexcess-precision=standard, the use of
1775 # x87 floating point operations leads to problems like isinf possibly returning
1776 # false for a value that is infinite when converted from the 80bit register to
1777 # the 8byte memory representation.
1779 # Only perform the test if the compiler doesn't understand
1780 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1781 # automatically.
1782 if '-fexcess-precision=standard' not in cflags
1783   if not cc.compiles('''
1784 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1785 choke me
1786 #endif''',
1787       name: '', args: test_c_args)
1788     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1789   endif
1790 endif
1794 ###############################################################
1795 # Compiler flags
1796 ###############################################################
1798 common_functional_flags = [
1799   # Disable strict-aliasing rules; needed for gcc 3.3+
1800   '-fno-strict-aliasing',
1801   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1802   '-fwrapv',
1803   '-fexcess-precision=standard',
1806 cflags += cc.get_supported_arguments(common_functional_flags)
1807 if llvm.found()
1808   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1809 endif
1811 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1812 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1814 common_warning_flags = [
1815   '-Wmissing-prototypes',
1816   '-Wpointer-arith',
1817   # Really don't want VLAs to be used in our dialect of C
1818   '-Werror=vla',
1819   # On macOS, complain about usage of symbols newer than the deployment target
1820   '-Werror=unguarded-availability-new',
1821   '-Wendif-labels',
1822   '-Wmissing-format-attribute',
1823   '-Wimplicit-fallthrough=3',
1824   '-Wcast-function-type',
1825   '-Wshadow=compatible-local',
1826   # This was included in -Wall/-Wformat in older GCC versions
1827   '-Wformat-security',
1830 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1831 if llvm.found()
1832   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1833 endif
1835 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1836 # the result for them
1837 cflags_no_decl_after_statement = []
1838 if cc.has_argument('-Wdeclaration-after-statement')
1839   cflags_warn += '-Wdeclaration-after-statement'
1840   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1841 endif
1844 # The following tests want to suppress various unhelpful warnings by adding
1845 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1846 # switches, so we have to test for the positive form and if that works,
1847 # add the negative form.
1849 negative_warning_flags = [
1850   # Suppress clang's unhelpful unused-command-line-argument warnings.
1851   'unused-command-line-argument',
1853   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1854   # of warnings when building plperl because of usages in the Perl headers.
1855   'compound-token-split-by-macro',
1857   # Similarly disable useless truncation warnings from gcc 8+
1858   'format-truncation',
1859   'stringop-truncation',
1861   # Suppress clang 16's strict warnings about function casts
1862   'cast-function-type-strict',
1864   # To make warning_level=2 / -Wextra work, we'd need at least the following
1865   # 'clobbered',
1866   # 'missing-field-initializers',
1867   # 'sign-compare',
1868   # 'unused-parameter',
1871 foreach w : negative_warning_flags
1872   if cc.has_argument('-W' + w)
1873     cflags_warn += '-Wno-' + w
1874   endif
1875   if llvm.found() and cpp.has_argument('-W' + w)
1876     cxxflags_warn += '-Wno-' + w
1877   endif
1878 endforeach
1881 # From Project.pm
1882 if cc.get_id() == 'msvc'
1883   cflags_warn += [
1884     '/wd4018', # signed/unsigned mismatch
1885     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1886     '/wd4273', # inconsistent DLL linkage
1887     '/wd4101', # unreferenced local variable
1888     '/wd4102', # unreferenced label
1889     '/wd4090', # different 'modifier' qualifiers
1890     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1891   ]
1893   cppflags += [
1894     '/DWIN32',
1895     '/DWINDOWS',
1896     '/D__WINDOWS__',
1897     '/D__WIN32__',
1898     '/D_CRT_SECURE_NO_DEPRECATE',
1899     '/D_CRT_NONSTDC_NO_DEPRECATE',
1900   ]
1902   # We never need export libraries. As link.exe reports their creation, they
1903   # are unnecessarily noisy. Similarly, we don't need import library for
1904   # modules, we only import them dynamically, and they're also noisy.
1905   ldflags += '/NOEXP'
1906   ldflags_mod += '/NOIMPLIB'
1907 endif
1911 ###############################################################
1912 # Atomics
1913 ###############################################################
1915 if not get_option('spinlocks')
1916   warning('Not using spinlocks will cause poor performance')
1917 else
1918   cdata.set('HAVE_SPINLOCKS', 1)
1919 endif
1921 if not get_option('atomics')
1922   warning('Not using atomics will cause poor performance')
1923 else
1924   # XXX: perhaps we should require some atomics support in this case these
1925   # days?
1926   cdata.set('HAVE_ATOMICS', 1)
1928   atomic_checks = [
1929     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1930      'desc': '__sync_lock_test_and_set(char)',
1931      'test': '''
1932 char lock = 0;
1933 __sync_lock_test_and_set(&lock, 1);
1934 __sync_lock_release(&lock);'''},
1936     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1937      'desc': '__sync_lock_test_and_set(int32)',
1938      'test': '''
1939 int lock = 0;
1940 __sync_lock_test_and_set(&lock, 1);
1941 __sync_lock_release(&lock);'''},
1943     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1944      'desc': '__sync_val_compare_and_swap(int32)',
1945      'test': '''
1946 int val = 0;
1947 __sync_val_compare_and_swap(&val, 0, 37);'''},
1949     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1950      'desc': '__sync_val_compare_and_swap(int64)',
1951      'test': '''
1952 INT64 val = 0;
1953 __sync_val_compare_and_swap(&val, 0, 37);'''},
1955     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1956      'desc': ' __atomic_compare_exchange_n(int32)',
1957      'test': '''
1958 int val = 0;
1959 int expect = 0;
1960 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1962     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1963      'desc': ' __atomic_compare_exchange_n(int64)',
1964      'test': '''
1965 INT64 val = 0;
1966 INT64 expect = 0;
1967 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1968   ]
1970   foreach check : atomic_checks
1971     test = '''
1972 int main(void)
1975 }'''.format(check['test'])
1977     cdata.set(check['name'],
1978       cc.links(test,
1979         name: check['desc'],
1980         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1981     )
1982   endforeach
1984 endif
1988 ###############################################################
1989 # Select CRC-32C implementation.
1991 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1992 # use the special CRC instructions for calculating CRC-32C. If we're not
1993 # targeting such a processor, but we can nevertheless produce code that uses
1994 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1995 # implementations and select which one to use at runtime, depending on whether
1996 # SSE 4.2 is supported by the processor we're running on.
1998 # Similarly, if we are targeting an ARM processor that has the CRC
1999 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2000 # we're not targeting such a processor, but can nevertheless produce code that
2001 # uses the CRC instructions, compile both, and select at runtime.
2002 ###############################################################
2004 have_optimized_crc = false
2005 cflags_crc = []
2006 if host_cpu == 'x86' or host_cpu == 'x86_64'
2008   if cc.get_id() == 'msvc'
2009     cdata.set('USE_SSE42_CRC32C', false)
2010     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2011     have_optimized_crc = true
2012   else
2014     prog = '''
2015 #include <nmmintrin.h>
2017 int main(void)
2019     unsigned int crc = 0;
2020     crc = _mm_crc32_u8(crc, 0);
2021     crc = _mm_crc32_u32(crc, 0);
2022     /* return computed value, to prevent the above being optimized away */
2023     return crc == 0;
2027     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2028           args: test_c_args)
2029       # Use Intel SSE 4.2 unconditionally.
2030       cdata.set('USE_SSE42_CRC32C', 1)
2031       have_optimized_crc = true
2032     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2033           args: test_c_args + ['-msse4.2'])
2034       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2035       # the runtime check.
2036       cflags_crc += '-msse4.2'
2037       cdata.set('USE_SSE42_CRC32C', false)
2038       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2039       have_optimized_crc = true
2040     endif
2042   endif
2044 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2046   prog = '''
2047 #include <arm_acle.h>
2049 int main(void)
2051     unsigned int crc = 0;
2052     crc = __crc32cb(crc, 0);
2053     crc = __crc32ch(crc, 0);
2054     crc = __crc32cw(crc, 0);
2055     crc = __crc32cd(crc, 0);
2057     /* return computed value, to prevent the above being optimized away */
2058     return crc == 0;
2062   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2063       args: test_c_args)
2064     # Use ARM CRC Extension unconditionally
2065     cdata.set('USE_ARMV8_CRC32C', 1)
2066     have_optimized_crc = true
2067   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2068       args: test_c_args + ['-march=armv8-a+crc'])
2069     # Use ARM CRC Extension, with runtime check
2070     cflags_crc += '-march=armv8-a+crc'
2071     cdata.set('USE_ARMV8_CRC32C', false)
2072     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2073     have_optimized_crc = true
2074   endif
2075 endif
2077 if not have_optimized_crc
2078   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2079   # support.
2080   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2081 endif
2085 ###############################################################
2086 # Other CPU specific stuff
2087 ###############################################################
2089 if host_cpu == 'x86_64'
2091   if cc.compiles('''
2092       void main(void)
2093       {
2094           long long x = 1; long long r;
2095           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2096       }''',
2097       name: '@0@: popcntq instruction'.format(host_cpu),
2098       args: test_c_args)
2099     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2100   endif
2102 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2103   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2104   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2105     if cc.compiles('''
2106       static inline int
2107       addi(int ra, int si)
2108       {
2109           int res = 0;
2110           if (__builtin_constant_p(si))
2111               __asm__ __volatile__(
2112                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2113           return res;
2114       }
2115       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2116       ''',
2117       args: test_c_args)
2118       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2119     endif
2120   endif
2121 endif
2125 ###############################################################
2126 # Library / OS tests
2127 ###############################################################
2129 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2130 # unnecessary checks over and over, particularly on windows.
2131 header_checks = [
2132   'atomic.h',
2133   'copyfile.h',
2134   'crtdefs.h',
2135   'execinfo.h',
2136   'getopt.h',
2137   'ifaddrs.h',
2138   'langinfo.h',
2139   'mbarrier.h',
2140   'stdbool.h',
2141   'strings.h',
2142   'sys/epoll.h',
2143   'sys/event.h',
2144   'sys/personality.h',
2145   'sys/prctl.h',
2146   'sys/procctl.h',
2147   'sys/signalfd.h',
2148   'sys/ucred.h',
2149   'termios.h',
2150   'ucred.h',
2153 foreach header : header_checks
2154   varname = 'HAVE_' + header.underscorify().to_upper()
2156   # Emulate autoconf behaviour of not-found->undef, found->1
2157   found = cc.has_header(header,
2158     include_directories: postgres_inc, args: test_c_args)
2159   cdata.set(varname, found ? 1 : false,
2160             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2161 endforeach
2164 decl_checks = [
2165   ['F_FULLFSYNC', 'fcntl.h'],
2166   ['fdatasync', 'unistd.h'],
2167   ['posix_fadvise', 'fcntl.h'],
2168   ['strlcat', 'string.h'],
2169   ['strlcpy', 'string.h'],
2170   ['strnlen', 'string.h'],
2173 # Need to check for function declarations for these functions, because
2174 # checking for library symbols wouldn't handle deployment target
2175 # restrictions on macOS
2176 decl_checks += [
2177   ['preadv', 'sys/uio.h'],
2178   ['pwritev', 'sys/uio.h'],
2181 foreach c : decl_checks
2182   func = c.get(0)
2183   header = c.get(1)
2184   args = c.get(2, {})
2185   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2187   found = cc.has_header_symbol(header, func,
2188     args: test_c_args, include_directories: postgres_inc,
2189     kwargs: args)
2190   cdata.set10(varname, found, description:
2191 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2192    don't.'''.format(func))
2193 endforeach
2196 if cc.has_type('struct option',
2197     args: test_c_args, include_directories: postgres_inc,
2198     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2199   cdata.set('HAVE_STRUCT_OPTION', 1)
2200 endif
2203 foreach c : ['opterr', 'optreset']
2204   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2206   if cc.links('''
2207 #include <unistd.h>
2208 int main(void)
2210     extern int @0@;
2211     @0@ = 1;
2213 '''.format(c), name: c, args: test_c_args)
2214     cdata.set(varname, 1)
2215   else
2216     cdata.set(varname, false)
2217   endif
2218 endforeach
2220 if cc.has_type('socklen_t',
2221     args: test_c_args, include_directories: postgres_inc,
2222     prefix: '''
2223 #include <sys/socket.h>''')
2224   cdata.set('HAVE_SOCKLEN_T', 1)
2225 endif
2227 if cc.has_member('struct sockaddr', 'sa_len',
2228     args: test_c_args, include_directories: postgres_inc,
2229     prefix: '''
2230 #include <sys/types.h>
2231 #include <sys/socket.h>''')
2232   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2233 endif
2235 if cc.has_member('struct tm', 'tm_zone',
2236     args: test_c_args, include_directories: postgres_inc,
2237     prefix: '''
2238 #include <sys/types.h>
2239 #include <time.h>
2240 ''')
2241   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2242 endif
2244 if cc.compiles('''
2245 #include <time.h>
2246 extern int foo(void);
2247 int foo(void)
2249     return timezone / 60;
2251 ''',
2252     name: 'global variable `timezone\' exists',
2253     args: test_c_args, include_directories: postgres_inc)
2254   cdata.set('HAVE_INT_TIMEZONE', 1)
2255 else
2256   cdata.set('HAVE_INT_TIMEZONE', false)
2257 endif
2259 if cc.has_type('union semun',
2260     args: test_c_args,
2261     include_directories: postgres_inc,
2262     prefix: '''
2263 #include <sys/types.h>
2264 #include <sys/ipc.h>
2265 #include <sys/sem.h>
2266 ''')
2267   cdata.set('HAVE_UNION_SEMUN', 1)
2268 endif
2270 if cc.compiles('''
2271 #include <string.h>
2272 int main(void)
2274   char buf[100];
2275   switch (strerror_r(1, buf, sizeof(buf)))
2276   { case 0: break; default: break; }
2277 }''',
2278     name: 'strerror_r',
2279     args: test_c_args, include_directories: postgres_inc)
2280   cdata.set('STRERROR_R_INT', 1)
2281 else
2282   cdata.set('STRERROR_R_INT', false)
2283 endif
2285 # Check for the locale_t type and find the right header file.  macOS
2286 # needs xlocale.h; standard is locale.h, but glibc also has an
2287 # xlocale.h file that we should not use.  MSVC has a replacement
2288 # defined in src/include/port/win32_port.h.
2289 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2290   cdata.set('HAVE_LOCALE_T', 1)
2291 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2292   cdata.set('HAVE_LOCALE_T', 1)
2293   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2294 elif cc.get_id() == 'msvc'
2295   cdata.set('HAVE_LOCALE_T', 1)
2296 endif
2298 # Check if the C compiler understands typeof or a variant.  Define
2299 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2300 foreach kw : ['typeof', '__typeof__', 'decltype']
2301   if cc.compiles('''
2302 int main(void)
2304     int x = 0;
2305     @0@(x) y;
2306     y = x;
2307     return y;
2309 '''.format(kw),
2310     name: 'typeof()',
2311     args: test_c_args, include_directories: postgres_inc)
2313     cdata.set('HAVE_TYPEOF', 1)
2314     if kw != 'typeof'
2315       cdata.set('typeof', kw)
2316     endif
2318     break
2319   endif
2320 endforeach
2323 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2324 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2325 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2326 wcstombs_l_test = '''
2327 #include <stdlib.h>
2328 #include <locale.h>
2331 void main(void)
2333 #ifndef wcstombs_l
2334     (void) wcstombs_l;
2335 #endif
2338 if (not cc.compiles(wcstombs_l_test.format(''),
2339       name: 'wcstombs_l') and
2340     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2341       name: 'wcstombs_l in xlocale.h'))
2342     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2343 endif
2346 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2347 # understands, because it conflicts with __declspec(restrict). Therefore we
2348 # define pg_restrict to the appropriate definition, which presumably won't
2349 # conflict.
2351 # We assume C99 support, so we don't need to make this conditional.
2353 # XXX: Historically we allowed platforms to disable restrict in template
2354 # files, but that was only added for AIX when building with XLC, which we
2355 # don't support yet.
2356 cdata.set('pg_restrict', '__restrict')
2359 # Most libraries are included only if they demonstrably provide a function we
2360 # need, but libm is an exception: always include it, because there are too
2361 # many compilers that play cute optimization games that will break probes for
2362 # standard functions such as pow().
2363 os_deps += cc.find_library('m', required: false)
2365 rt_dep = cc.find_library('rt', required: false)
2367 dl_dep = cc.find_library('dl', required: false)
2369 util_dep = cc.find_library('util', required: false)
2370 posix4_dep = cc.find_library('posix4', required: false)
2372 getopt_dep = cc.find_library('getopt', required: false)
2373 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2374 # Check if we want to replace getopt/getopt_long even if provided by the system
2375 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2376 #   so always use our version on Windows
2377 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2378 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2379 # - We want to use system's getopt_long() only if the system provides struct
2380 #   option
2381 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2382 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2384 # Required on BSDs
2385 execinfo_dep = cc.find_library('execinfo', required: false)
2387 if host_system == 'cygwin'
2388   cygipc_dep = cc.find_library('cygipc', required: false)
2389 else
2390   cygipc_dep = not_found_dep
2391 endif
2393 if host_system == 'sunos'
2394   socket_dep = cc.find_library('socket', required: false)
2395 else
2396   socket_dep = not_found_dep
2397 endif
2399 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2400 # unnecessary checks over and over, particularly on windows.
2401 func_checks = [
2402   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2403   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2404   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2405   ['copyfile'],
2406   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2407   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2408   # required. Just checking for dlsym() ought to suffice.
2409   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2410   ['explicit_bzero'],
2411   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2412   ['getifaddrs'],
2413   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2414   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2415   ['getpeereid'],
2416   ['getpeerucred'],
2417   ['inet_aton'],
2418   ['inet_pton'],
2419   ['kqueue'],
2420   ['mbstowcs_l'],
2421   ['memset_s'],
2422   ['mkdtemp'],
2423   ['posix_fadvise'],
2424   ['posix_fallocate'],
2425   ['ppoll'],
2426   ['pstat'],
2427   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2428   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2429   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2430   ['setproctitle', {'dependencies': [util_dep]}],
2431   ['setproctitle_fast'],
2432   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2433   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2434   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2435   ['socket', {'dependencies': [socket_dep], 'define': false}],
2436   ['strchrnul'],
2437   ['strerror_r', {'dependencies': [thread_dep]}],
2438   ['strlcat'],
2439   ['strlcpy'],
2440   ['strnlen'],
2441   ['strsignal'],
2442   ['sync_file_range'],
2443   ['syncfs'],
2444   ['uselocale'],
2445   ['wcstombs_l'],
2448 func_check_results = {}
2449 foreach c : func_checks
2450   func = c.get(0)
2451   kwargs = c.get(1, {})
2452   deps = kwargs.get('dependencies', [])
2454   if kwargs.get('skip', false)
2455     continue
2456   endif
2458   found = cc.has_function(func, args: test_c_args)
2460   if not found
2461     foreach dep : deps
2462       if not dep.found()
2463         continue
2464       endif
2465       found = cc.has_function(func, args: test_c_args,
2466                               dependencies: [dep])
2467       if found
2468         os_deps += dep
2469         break
2470       endif
2471     endforeach
2472   endif
2474   func_check_results += {func: found}
2476   if kwargs.get('define', true)
2477     # Emulate autoconf behaviour of not-found->undef, found->1
2478     cdata.set('HAVE_' + func.underscorify().to_upper(),
2479               found  ? 1 : false,
2480               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2481   endif
2482 endforeach
2485 if cc.has_function('syslog', args: test_c_args) and \
2486     cc.check_header('syslog.h', args: test_c_args)
2487   cdata.set('HAVE_SYSLOG', 1)
2488 endif
2491 # MSVC has replacements defined in src/include/port/win32_port.h.
2492 if cc.get_id() == 'msvc'
2493   cdata.set('HAVE_WCSTOMBS_L', 1)
2494   cdata.set('HAVE_MBSTOWCS_L', 1)
2495 endif
2498 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2499 # semaphores
2500 if sema_kind == 'unnamed_posix' and \
2501    not func_check_results.get('sem_init', false)
2502   sema_kind = 'sysv'
2503 endif
2505 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2506 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2508 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2509 cdata.set_quoted('DLSUFFIX', dlsuffix)
2512 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2513 cdata.set_quoted('PG_VERSION_STR',
2514   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2515     pg_version, host_machine.cpu_family(), host_system,
2516     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2517   )
2522 ###############################################################
2523 # Threading
2524 ###############################################################
2526 # XXX: About to rely on thread safety in the autoconf build, so not worth
2527 # implementing a fallback.
2528 cdata.set('ENABLE_THREAD_SAFETY', 1)
2532 ###############################################################
2533 # NLS / Gettext
2534 ###############################################################
2536 nlsopt = get_option('nls')
2537 libintl = not_found_dep
2539 if not nlsopt.disabled()
2540   # otherwise there'd be lots of
2541   # "Gettext not found, all translation (po) targets will be ignored."
2542   # warnings if not found.
2543   msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2545   # meson 0.59 has this wrapped in dependency('intl')
2546   if (msgfmt.found() and
2547       cc.check_header('libintl.h', required: nlsopt,
2548         args: test_c_args, include_directories: postgres_inc))
2550     # in libc
2551     if cc.has_function('ngettext')
2552       libintl = declare_dependency()
2553     else
2554       libintl = cc.find_library('intl',
2555         has_headers: ['libintl.h'], required: nlsopt,
2556         header_include_directories: postgres_inc,
2557         dirs: test_lib_d)
2558     endif
2559   endif
2561   if libintl.found()
2562     i18n = import('i18n')
2563     cdata.set('ENABLE_NLS', 1)
2564   endif
2565 endif
2569 ###############################################################
2570 # Build
2571 ###############################################################
2573 # Set up compiler / linker arguments to be used everywhere, individual targets
2574 # can add further args directly, or indirectly via dependencies
2575 add_project_arguments(cflags, language: ['c'])
2576 add_project_arguments(cppflags, language: ['c'])
2577 add_project_arguments(cflags_warn, language: ['c'])
2578 add_project_arguments(cxxflags, language: ['cpp'])
2579 add_project_arguments(cppflags, language: ['cpp'])
2580 add_project_arguments(cxxflags_warn, language: ['cpp'])
2581 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2584 # Collect a number of lists of things while recursing through the source
2585 # tree. Later steps then can use those.
2587 # list of targets for various alias targets
2588 backend_targets = []
2589 bin_targets = []
2590 pl_targets = []
2591 contrib_targets = []
2592 testprep_targets = []
2593 nls_targets = []
2596 # Define the tests to distribute them to the correct test styles later
2597 test_deps = []
2598 tests = []
2601 # Default options for targets
2603 # First identify rpaths
2604 bin_install_rpaths = []
2605 lib_install_rpaths = []
2606 mod_install_rpaths = []
2609 # Don't add rpaths on darwin for now - as long as only absolute references to
2610 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2611 # their final destination.
2612 if host_system != 'darwin'
2613   # Add absolute path to libdir to rpath. This ensures installed binaries /
2614   # libraries find our libraries (mainly libpq).
2615   bin_install_rpaths += dir_prefix / dir_lib
2616   lib_install_rpaths += dir_prefix / dir_lib
2617   mod_install_rpaths += dir_prefix / dir_lib
2619   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2620   #
2621   # Not needed on darwin even if we use relative rpaths for our own libraries,
2622   # as the install_name of libraries in extra_lib_dirs will point to their
2623   # location anyway.
2624   bin_install_rpaths += postgres_lib_d
2625   lib_install_rpaths += postgres_lib_d
2626   mod_install_rpaths += postgres_lib_d
2627 endif
2630 # Define arguments for default targets
2632 default_target_args = {
2633   'implicit_include_directories': false,
2634   'install': true,
2637 default_lib_args = default_target_args + {
2638   'name_prefix': '',
2641 internal_lib_args = default_lib_args + {
2642   'build_by_default': false,
2643   'install': false,
2646 default_mod_args = default_lib_args + {
2647   'name_prefix': '',
2648   'install_dir': dir_lib_pkg,
2651 default_bin_args = default_target_args + {
2652   'install_dir': dir_bin,
2655 if get_option('rpath')
2656   default_lib_args += {
2657     'install_rpath': ':'.join(lib_install_rpaths),
2658   }
2660   default_mod_args += {
2661     'install_rpath': ':'.join(mod_install_rpaths),
2662   }
2664   default_bin_args += {
2665     'install_rpath': ':'.join(bin_install_rpaths),
2666   }
2667 endif
2670 # Helper for exporting a limited number of symbols
2671 gen_export_kwargs = {
2672   'input': 'exports.txt',
2673   'output': '@BASENAME@.'+export_file_suffix,
2674   'command': [perl, files('src/tools/gen_export.pl'),
2675    '--format', export_file_format,
2676    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2677   'build_by_default': false,
2678   'install': false,
2684 ### Helpers for custom targets used across the tree
2687 catalog_pm = files('src/backend/catalog/Catalog.pm')
2688 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2689 gen_kwlist_deps = [perfect_hash_pm]
2690 gen_kwlist_cmd = [
2691   perl, '-I', '@SOURCE_ROOT@/src/tools',
2692   files('src/tools/gen_keywordlist.pl'),
2693   '--output', '@OUTDIR@', '@INPUT@']
2698 ### windows resources related stuff
2701 if host_system == 'windows'
2702   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2703   win32ver_rc = files('src/port/win32ver.rc')
2704   rcgen = find_program('src/tools/rcgen', native: true)
2706   rcgen_base_args = [
2707     '--srcdir', '@SOURCE_DIR@',
2708     '--builddir', meson.build_root(),
2709     '--rcout', '@OUTPUT0@',
2710     '--out', '@OUTPUT1@',
2711     '--input', '@INPUT@',
2712     '@EXTRA_ARGS@',
2713   ]
2715   if cc.get_argument_syntax() == 'msvc'
2716     rc = find_program('rc', required: true)
2717     rcgen_base_args += ['--rc', rc.path()]
2718     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2719   else
2720     windres = find_program('windres', required: true)
2721     rcgen_base_args += ['--windres', windres.path()]
2722     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2723   endif
2725   # msbuild backend doesn't support this atm
2726   if meson.backend() == 'ninja'
2727     rcgen_base_args += ['--depfile', '@DEPFILE@']
2728   endif
2730   rcgen_bin_args = rcgen_base_args + [
2731     '--VFT_TYPE', 'VFT_APP',
2732     '--FILEENDING', 'exe',
2733     '--ICO', pg_ico
2734   ]
2736   rcgen_lib_args = rcgen_base_args + [
2737     '--VFT_TYPE', 'VFT_DLL',
2738     '--FILEENDING', 'dll',
2739   ]
2741   rc_bin_gen = generator(rcgen,
2742     depfile: '@BASENAME@.d',
2743     arguments: rcgen_bin_args,
2744     output: rcgen_outputs,
2745   )
2747   rc_lib_gen = generator(rcgen,
2748     depfile: '@BASENAME@.d',
2749     arguments: rcgen_lib_args,
2750     output: rcgen_outputs,
2751   )
2752 endif
2756 # headers that the whole build tree depends on
2757 generated_headers = []
2758 # headers that the backend build depends on
2759 generated_backend_headers = []
2760 # configure_files() output, needs a way of converting to file names
2761 configure_files = []
2763 # generated files that might conflict with a partial in-tree autoconf build
2764 generated_sources = []
2765 # same, for paths that differ between autoconf / meson builds
2766 # elements are [dir, [files]]
2767 generated_sources_ac = {}
2770 # First visit src/include - all targets creating headers are defined
2771 # within. That makes it easy to add the necessary dependencies for the
2772 # subsequent build steps.
2774 subdir('src/include')
2776 subdir('config')
2778 # Then through src/port and src/common, as most other things depend on them
2780 frontend_port_code = declare_dependency(
2781   compile_args: ['-DFRONTEND'],
2782   include_directories: [postgres_inc],
2783   dependencies: os_deps,
2786 backend_port_code = declare_dependency(
2787   compile_args: ['-DBUILDING_DLL'],
2788   include_directories: [postgres_inc],
2789   sources: [errcodes], # errcodes.h is needed due to use of ereport
2790   dependencies: os_deps,
2793 subdir('src/port')
2795 frontend_common_code = declare_dependency(
2796   compile_args: ['-DFRONTEND'],
2797   include_directories: [postgres_inc],
2798   sources: generated_headers,
2799   dependencies: [os_deps, zlib, zstd],
2802 backend_common_code = declare_dependency(
2803   compile_args: ['-DBUILDING_DLL'],
2804   include_directories: [postgres_inc],
2805   sources: generated_headers,
2806   dependencies: [os_deps, zlib, zstd],
2809 subdir('src/common')
2811 # all shared libraries should depend on shlib_code
2812 shlib_code = declare_dependency(
2813   link_args: ldflags_sl,
2816 # all static libraries not part of the backend should depend on this
2817 frontend_stlib_code = declare_dependency(
2818   include_directories: [postgres_inc],
2819   link_with: [common_static, pgport_static],
2820   sources: generated_headers,
2821   dependencies: [os_deps, libintl],
2824 # all shared libraries not part of the backend should depend on this
2825 frontend_shlib_code = declare_dependency(
2826   include_directories: [postgres_inc],
2827   link_with: [common_shlib, pgport_shlib],
2828   sources: generated_headers,
2829   dependencies: [shlib_code, os_deps, libintl],
2832 # Dependencies both for static and shared libpq
2833 libpq_deps += [
2834   thread_dep,
2836   gssapi,
2837   ldap_r,
2838   libintl,
2839   ssl,
2842 subdir('src/interfaces/libpq')
2843 # fe_utils depends on libpq
2844 subdir('src/fe_utils')
2846 # for frontend binaries
2847 frontend_code = declare_dependency(
2848   include_directories: [postgres_inc],
2849   link_with: [fe_utils, common_static, pgport_static],
2850   sources: generated_headers,
2851   dependencies: [os_deps, libintl],
2854 backend_both_deps += [
2855   thread_dep,
2856   bsd_auth,
2857   gssapi,
2858   icu,
2859   icu_i18n,
2860   ldap,
2861   libintl,
2862   libxml,
2863   lz4,
2864   pam,
2865   ssl,
2866   systemd,
2867   zlib,
2868   zstd,
2871 backend_mod_deps = backend_both_deps + os_deps
2873 backend_code = declare_dependency(
2874   compile_args: ['-DBUILDING_DLL'],
2875   include_directories: [postgres_inc],
2876   link_args: ldflags_be,
2877   link_with: [],
2878   sources: generated_headers + generated_backend_headers,
2879   dependencies: os_deps + backend_both_deps + backend_deps,
2882 # install these files only during test, not main install
2883 test_install_data = []
2884 test_install_libs = []
2886 # src/backend/meson.build defines backend_mod_code used for extension
2887 # libraries.
2890 # Then through the main sources. That way contrib can have dependencies on
2891 # main sources. Note that this explicitly doesn't enter src/test, right now a
2892 # few regression tests depend on contrib files.
2894 subdir('src')
2896 subdir('contrib')
2898 subdir('src/test')
2899 subdir('src/interfaces/libpq/test')
2900 subdir('src/interfaces/ecpg/test')
2902 subdir('doc/src/sgml')
2904 generated_sources_ac += {'': ['GNUmakefile']}
2906 # After processing src/test, add test_install_libs to the testprep_targets
2907 # to build them
2908 testprep_targets += test_install_libs
2911 # If there are any files in the source directory that we also generate in the
2912 # build directory, they might get preferred over the newly generated files,
2913 # e.g. because of a #include "file", which always will search in the current
2914 # directory first.
2915 message('checking for file conflicts between source and build directory')
2916 conflicting_files = []
2917 potentially_conflicting_files_t = []
2918 potentially_conflicting_files_t += generated_headers
2919 potentially_conflicting_files_t += generated_backend_headers
2920 potentially_conflicting_files_t += generated_backend_sources
2921 potentially_conflicting_files_t += generated_sources
2923 potentially_conflicting_files = []
2925 # convert all sources of potentially conflicting files into uniform shape
2926 foreach t : potentially_conflicting_files_t
2927   potentially_conflicting_files += t.full_path()
2928 endforeach
2929 foreach t : configure_files
2930   t = '@0@'.format(t)
2931   potentially_conflicting_files += meson.current_build_dir() / t
2932 endforeach
2933 foreach sub, fnames : generated_sources_ac
2934   sub = meson.build_root() / sub
2935   foreach fname : fnames
2936     potentially_conflicting_files += sub / fname
2937   endforeach
2938 endforeach
2940 # find and report conflicting files
2941 foreach build_path : potentially_conflicting_files
2942   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2943   # str.replace is in 0.56
2944   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2945   if fs.exists(src_path) or fs.is_symlink(src_path)
2946     conflicting_files += src_path
2947   endif
2948 endforeach
2949 # XXX: Perhaps we should generate a file that would clean these up? The list
2950 # can be long.
2951 if conflicting_files.length() > 0
2952   errmsg_cleanup = '''
2953 Conflicting files in source directory:
2954   @0@
2956 The conflicting files need to be removed, either by removing the files listed
2957 above, or by running configure and then make maintainer-clean.
2959   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2960   error(errmsg_nonclean_base.format(errmsg_cleanup))
2961 endif
2965 ###############################################################
2966 # Install targets
2967 ###############################################################
2970 # We want to define additional install targets beyond what meson provides. For
2971 # that we need to define targets depending on nearly everything. We collected
2972 # the results of i18n.gettext() invocations into nls_targets, that also
2973 # includes maintainer targets though. Collect the ones we want as a dependency.
2975 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
2976 # generation happens during install, so that's not a real issue.
2977 nls_mo_targets = []
2978 if libintl.found() and meson.version().version_compare('>=0.60')
2979   # use range() to avoid the flattening of the list that foreach() would do
2980   foreach off : range(0, nls_targets.length())
2981     # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
2982     # -pot target 3) maintainer -pot target
2983     nls_mo_targets += nls_targets[off][0]
2984   endforeach
2985   alias_target('nls', nls_mo_targets)
2986 endif
2989 all_built = [
2990   backend_targets,
2991   bin_targets,
2992   libpq_st,
2993   pl_targets,
2994   contrib_targets,
2995   nls_mo_targets,
2996   testprep_targets,
2997   ecpg_targets,
3000 # Meson's default install target is quite verbose. Provide one that is quiet.
3001 install_quiet = custom_target('install-quiet',
3002   output: 'install-quiet',
3003   build_always_stale: true,
3004   build_by_default: false,
3005   command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3006   depends: all_built,
3009 # Target to install files used for tests, which aren't installed by default
3010 install_test_files_args = [
3011   install_files,
3012   '--prefix', dir_prefix,
3013   '--install', contrib_data_dir, test_install_data,
3014   '--install', dir_lib_pkg, test_install_libs,
3016 run_target('install-test-files',
3017   command: [python] + install_test_files_args,
3018   depends: testprep_targets,
3023 ###############################################################
3024 # Test prep
3025 ###############################################################
3027 # DESTDIR for the installation we'll run tests in
3028 test_install_destdir = meson.build_root() / 'tmp_install/'
3030 # DESTDIR + prefix appropriately munged
3031 if build_system != 'windows'
3032   # On unixoid systems this is trivial, we just prepend the destdir
3033   assert(dir_prefix.startswith('/')) # enforced by meson
3034   test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3035 else
3036   # drives, drive-relative paths, etc make this complicated on windows, call
3037   # into a copy of meson's logic for it
3038   command = [
3039     python, '-c',
3040     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3041     test_install_destdir, dir_prefix]
3042   test_install_location = run_command(command, check: true).stdout().strip()
3043 endif
3045 meson_install_args = meson_args + ['install'] + {
3046     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3047     'muon': []
3048 }[meson_impl]
3050 # setup tests should be run first,
3051 # so define priority for these
3052 setup_tests_priority = 100
3053 test('tmp_install',
3054     meson_bin, args: meson_install_args ,
3055     env: {'DESTDIR':test_install_destdir},
3056     priority: setup_tests_priority,
3057     timeout: 300,
3058     is_parallel: false,
3059     suite: ['setup'])
3061 test('install_test_files',
3062     python,
3063     args: install_test_files_args + ['--destdir', test_install_destdir],
3064     priority: setup_tests_priority,
3065     is_parallel: false,
3066     suite: ['setup'])
3068 test_result_dir = meson.build_root() / 'testrun'
3071 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3072 # inevitable conflicts from running tests in parallel, hackishly assign
3073 # different ports for different tests.
3075 testport = 40000
3077 test_env = environment()
3079 temp_install_bindir = test_install_location / get_option('bindir')
3080 test_env.set('PG_REGRESS', pg_regress.full_path())
3081 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3083 # Test suites that are not safe by default but can be run if selected
3084 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3085 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3086 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3088 # Add the temporary installation to the library search path on platforms where
3089 # that works (everything but windows, basically). On windows everything
3090 # library-like gets installed into bindir, solving that issue.
3091 if library_path_var != ''
3092   test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3093 endif
3097 ###############################################################
3098 # Test Generation
3099 ###############################################################
3101 # When using a meson version understanding exclude_suites, define a
3102 # 'tmp_install' test setup (the default) that excludes tests running against a
3103 # pre-existing install and a 'running' setup that conflicts with creation of
3104 # the temporary installation and tap tests (which don't support running
3105 # against a running server).
3107 running_suites = []
3108 install_suites = []
3109 if meson.version().version_compare('>=0.57')
3110   runningcheck = true
3111 else
3112   runningcheck = false
3113 endif
3115 testwrap = files('src/tools/testwrap')
3117 foreach test_dir : tests
3118   testwrap_base = [
3119     testwrap,
3120     '--basedir', meson.build_root(),
3121     '--srcdir', test_dir['sd'],
3122   ]
3124   foreach kind, v : test_dir
3125     if kind in ['sd', 'bd', 'name']
3126       continue
3127     endif
3129     t = test_dir[kind]
3131     if kind in ['regress', 'isolation', 'ecpg']
3132       if kind == 'regress'
3133         runner = pg_regress
3134         fallback_dbname = 'regression_@0@'
3135       elif kind == 'isolation'
3136         runner = pg_isolation_regress
3137         fallback_dbname = 'isolation_regression_@0@'
3138       elif kind == 'ecpg'
3139         runner = pg_regress_ecpg
3140         fallback_dbname = 'ecpg_regression_@0@'
3141       endif
3143       test_group = test_dir['name']
3144       test_group_running = test_dir['name'] + '-running'
3146       test_output = test_result_dir / test_group / kind
3147       test_output_running = test_result_dir / test_group_running/ kind
3149       # Unless specified by the test, choose a non-conflicting database name,
3150       # to avoid conflicts when running against existing server.
3151       dbname = t.get('dbname',
3152         fallback_dbname.format(test_dir['name']))
3154       test_command_base = [
3155         runner.full_path(),
3156         '--inputdir', t.get('inputdir', test_dir['sd']),
3157         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3158         '--bindir', '',
3159         '--dlpath', test_dir['bd'],
3160         '--max-concurrent-tests=20',
3161         '--dbname', dbname,
3162       ] + t.get('regress_args', [])
3164       test_selection = []
3165       if t.has_key('schedule')
3166         test_selection += ['--schedule', t['schedule'],]
3167       endif
3169       if kind == 'isolation'
3170         test_selection += t.get('specs', [])
3171       else
3172         test_selection += t.get('sql', [])
3173       endif
3175       env = test_env
3176       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3178       test_kwargs = {
3179         'protocol': 'tap',
3180         'priority': 10,
3181         'timeout': 1000,
3182         'depends': test_deps + t.get('deps', []),
3183         'env': env,
3184       } + t.get('test_kwargs', {})
3186       test(test_group / kind,
3187         python,
3188         args: [
3189           testwrap_base,
3190           '--testgroup', test_group,
3191           '--testname', kind,
3192           '--',
3193           test_command_base,
3194           '--outputdir', test_output,
3195           '--temp-instance', test_output / 'tmp_check',
3196           '--port', testport.to_string(),
3197           test_selection,
3198         ],
3199         suite: test_group,
3200         kwargs: test_kwargs,
3201       )
3202       install_suites += test_group
3204       # some tests can't support running against running DB
3205       if runningcheck and t.get('runningcheck', true)
3206         test(test_group_running / kind,
3207           python,
3208           args: [
3209             testwrap_base,
3210             '--testgroup', test_group_running,
3211             '--testname', kind,
3212             '--',
3213             test_command_base,
3214             '--outputdir', test_output_running,
3215             test_selection,
3216           ],
3217           is_parallel: t.get('runningcheck-parallel', true),
3218           suite: test_group_running,
3219           kwargs: test_kwargs,
3220         )
3221         running_suites += test_group_running
3222       endif
3224       testport += 1
3225     elif kind == 'tap'
3226       if not tap_tests_enabled
3227         continue
3228       endif
3230       test_command = [
3231         perl.path(),
3232         '-I', meson.source_root() / 'src/test/perl',
3233         '-I', test_dir['sd'],
3234       ]
3236       # Add temporary install, the build directory for non-installed binaries and
3237       # also test/ for non-installed test binaries built separately.
3238       env = test_env
3239       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3241       foreach name, value : t.get('env', {})
3242         env.set(name, value)
3243       endforeach
3245       test_group = test_dir['name']
3246       test_kwargs = {
3247         'protocol': 'tap',
3248         'suite': test_group,
3249         'timeout': 1000,
3250         'depends': test_deps + t.get('deps', []),
3251         'env': env,
3252       } + t.get('test_kwargs', {})
3254       foreach onetap : t['tests']
3255         # Make tap test names prettier, remove t/ and .pl
3256         onetap_p = onetap
3257         if onetap_p.startswith('t/')
3258           onetap_p = onetap.split('t/')[1]
3259         endif
3260         if onetap_p.endswith('.pl')
3261           onetap_p = fs.stem(onetap_p)
3262         endif
3264         test(test_dir['name'] / onetap_p,
3265           python,
3266           kwargs: test_kwargs,
3267           args: testwrap_base + [
3268             '--testgroup', test_dir['name'],
3269             '--testname', onetap_p,
3270             '--', test_command,
3271             test_dir['sd'] / onetap,
3272           ],
3273         )
3274       endforeach
3275       install_suites += test_group
3276     else
3277       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3278     endif
3280   endforeach # kinds of tests
3282 endforeach # directories with tests
3284 # repeat condition so meson realizes version dependency
3285 if meson.version().version_compare('>=0.57')
3286   add_test_setup('tmp_install',
3287     is_default: true,
3288     exclude_suites: running_suites)
3289   add_test_setup('running',
3290     exclude_suites: ['setup'] + install_suites)
3291 endif
3295 ###############################################################
3296 # Pseudo targets
3297 ###############################################################
3299 alias_target('backend', backend_targets)
3300 alias_target('bin', bin_targets + [libpq_st])
3301 alias_target('pl', pl_targets)
3302 alias_target('contrib', contrib_targets)
3303 alias_target('testprep', testprep_targets)
3304 alias_target('install-world', install_quiet, installdocs)
3308 ###############################################################
3309 # The End, The End, My Friend
3310 ###############################################################
3312 if meson.version().version_compare('>=0.57')
3314   summary(
3315     {
3316       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3317       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3318       'segment size': get_option('segsize_blocks') != 0 ?
3319         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3320         '@0@ GB'.format(get_option('segsize')),
3321     },
3322     section: 'Data layout',
3323   )
3325   summary(
3326     {
3327       'host system': '@0@ @1@'.format(host_system, host_cpu),
3328       'build system': '@0@ @1@'.format(build_machine.system(),
3329                                        build_machine.cpu_family()),
3330     },
3331     section: 'System',
3332   )
3334   summary(
3335     {
3336       'linker': '@0@'.format(cc.get_linker_id()),
3337       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3338     },
3339     section: 'Compiler',
3340   )
3342   summary(
3343     {
3344       'CPP FLAGS': ' '.join(cppflags),
3345       'C FLAGS, functional': ' '.join(cflags),
3346       'C FLAGS, warnings': ' '.join(cflags_warn),
3347       'C FLAGS, modules': ' '.join(cflags_mod),
3348       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3349       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3350     },
3351     section: 'Compiler Flags',
3352   )
3354   if llvm.found()
3355     summary(
3356       {
3357         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3358       },
3359       section: 'Compiler',
3360     )
3362     summary(
3363       {
3364         'C++ FLAGS, functional': ' '.join(cxxflags),
3365         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3366         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3367       },
3368       section: 'Compiler Flags',
3369     )
3370   endif
3372   summary(
3373     {
3374       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3375       'dtrace': dtrace,
3376     },
3377     section: 'Programs',
3378   )
3380   summary(
3381     {
3382       'bonjour': bonjour,
3383       'bsd_auth': bsd_auth,
3384       'docs': docs_dep,
3385       'docs_pdf': docs_pdf_dep,
3386       'gss': gssapi,
3387       'icu': icu,
3388       'ldap': ldap,
3389       'libxml': libxml,
3390       'libxslt': libxslt,
3391       'llvm': llvm,
3392       'lz4': lz4,
3393       'nls': libintl,
3394       'openssl': ssl,
3395       'pam': pam,
3396       'plperl': perl_dep,
3397       'plpython': python3_dep,
3398       'pltcl': tcl_dep,
3399       'readline': readline,
3400       'selinux': selinux,
3401       'systemd': systemd,
3402       'uuid': uuid,
3403       'zlib': zlib,
3404       'zstd': zstd,
3405     },
3406     section: 'External libraries',
3407   )
3409 endif