Fix redefinition of type in commit e0ece2a981.
[pgsql.git] / meson.build
blobcfd654d291661f36375ed14e02ee26b77efc6c83
1 # Copyright (c) 2022-2025, 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: '18devel',
12   license: 'PostgreSQL',
14   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
15   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
16   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
17   meson_version: '>=0.54',
18   default_options: [
19     'warning_level=1', #-Wall equivalent
20     'b_pch=false',
21     'buildtype=debugoptimized', # -O2 + debug
22     # For compatibility with the autoconf build, set a default prefix. This
23     # works even on windows, where it's a drive-relative path (i.e. when on
24     # d:/somepath it'll install to d:/usr/local/pgsql)
25     'prefix=/usr/local/pgsql',
26   ]
31 ###############################################################
32 # Basic prep
33 ###############################################################
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
42 cc = meson.get_compiler('c')
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
46 auto_features = get_option('auto_features')
50 ###############################################################
51 # Safety first
52 ###############################################################
54 # It's very easy to get into confusing states when the source directory
55 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
56 # refuse to build in that case.
58 # There's a more elaborate check later, that checks for conflicts around all
59 # generated files. But we can only do that much further down the line, so this
60 # quick check seems worth it. Adhering to this advice should clean up the
61 # conflict, but won't protect against somebody doing make distclean or just
62 # removing pg_config.h
63 errmsg_nonclean_base = '''
64 ****
65 Non-clean source code directory detected.
67 To build with meson the source tree may not have an in-place, ./configure
68 style, build configured. You can have both meson and ./configure style builds
69 for the same source tree by building out-of-source / VPATH with
70 configure. Alternatively use a separate check out for meson based builds.
72 @0@
73 ****'''
74 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
75   errmsg_cleanup = 'To clean up, run make distclean in the source tree.'
76   error(errmsg_nonclean_base.format(errmsg_cleanup))
77 endif
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
88 postgres_lib_d = get_option('extra_lib_dirs')
90 cppflags = []
92 cflags = []
93 cxxflags = []
94 cflags_warn = []
95 cxxflags_warn = []
96 cflags_mod = []
97 cxxflags_mod = []
99 ldflags = []
100 ldflags_be = []
101 ldflags_sl = []
102 ldflags_mod = []
104 test_c_args = []
106 os_deps = []
107 backend_both_deps = []
108 backend_deps = []
109 libpq_deps = []
111 pg_sysroot = ''
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
122 pg_version = meson.project_version()
124 if pg_version.endswith('devel')
125   pg_version_arr = [pg_version.split('devel')[0], '0']
126 elif pg_version.contains('beta')
127   pg_version_arr = [pg_version.split('beta')[0], '0']
128 elif pg_version.contains('rc')
129   pg_version_arr = [pg_version.split('rc')[0], '0']
130 else
131   pg_version_arr = pg_version.split('.')
132 endif
134 pg_version_major = pg_version_arr[0].to_int()
135 pg_version_minor = pg_version_arr[1].to_int()
136 pg_version_num = (pg_version_major * 10000) + pg_version_minor
138 pg_url = 'https://www.postgresql.org/'
140 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
141 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
142 cdata.set_quoted('PACKAGE_URL', pg_url)
143 cdata.set_quoted('PACKAGE_VERSION', pg_version)
144 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
145 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
147 pg_version += get_option('extra_version')
148 cdata.set_quoted('PG_VERSION', pg_version)
149 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
150 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
151 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
152 cdata.set('PG_VERSION_NUM', pg_version_num)
153 # PG_VERSION_STR is built later, it depends on compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 exesuffix = '' # overridden below where necessary
163 dlsuffix = '.so' # overridden below where necessary
164 library_path_var = 'LD_LIBRARY_PATH'
166 # Format of file to control exports from libraries, and how to pass them to
167 # the compiler. For export_fmt @0@ is the path to the file export file.
168 export_file_format = 'gnu'
169 export_file_suffix = 'list'
170 export_fmt = '-Wl,--version-script=@0@'
172 # Flags to add when linking a postgres extension, @0@ is path to
173 # the relevant object on the platform.
174 mod_link_args_fmt = []
176 memset_loop_limit = 1024
178 # Choice of shared memory and semaphore implementation
179 shmem_kind = 'sysv'
180 sema_kind = 'sysv'
182 # We implement support for some operating systems by pretending they're
183 # another. Map here, before determining system properties below
184 if host_system == 'dragonfly'
185   # apparently the most similar
186   host_system = 'netbsd'
187 elif host_system == 'android'
188   # while android isn't quite a normal linux, it seems close enough
189   # for our purposes so far
190   host_system = 'linux'
191 endif
193 # meson's system names don't quite map to our "traditional" names. In some
194 # places we need the "traditional" name, e.g., for mapping
195 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
196 # that purpose.
197 portname = host_system
199 if host_system == 'cygwin'
200   sema_kind = 'unnamed_posix'
201   cppflags += '-D_GNU_SOURCE'
202   dlsuffix = '.dll'
203   mod_link_args_fmt = ['@0@']
204   mod_link_with_name = 'lib@0@.a'
205   mod_link_with_dir = 'libdir'
207 elif host_system == 'darwin'
208   dlsuffix = '.dylib'
209   library_path_var = 'DYLD_LIBRARY_PATH'
211   export_file_format = 'darwin'
212   export_fmt = '-Wl,-exported_symbols_list,@0@'
214   mod_link_args_fmt = ['-bundle_loader', '@0@']
215   mod_link_with_dir = 'bindir'
216   mod_link_with_name = '@0@'
218   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
219   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
220   message('darwin sysroot: @0@'.format(pg_sysroot))
221   if pg_sysroot != ''
222     cflags += ['-isysroot', pg_sysroot]
223     ldflags += ['-isysroot', pg_sysroot]
224   endif
226   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
227   # don't want because a) it's different from what we do for autoconf, b) it
228   # causes warnings in macOS Ventura. But using -Wl,-undefined,error causes a
229   # warning starting in Sonoma. So only add -Wl,-undefined,error if it does
230   # not cause a warning.
231   if cc.has_multi_link_arguments('-Wl,-undefined,error', '-Werror')
232     ldflags_mod += '-Wl,-undefined,error'
233   endif
235   # Starting in Sonoma, the linker warns about the same library being
236   # linked twice.  Which can easily happen when multiple dependencies
237   # depend on the same library. Quiesce the ill considered warning.
238   ldflags += cc.get_supported_link_arguments('-Wl,-no_warn_duplicate_libraries')
240 elif host_system == 'freebsd'
241   sema_kind = 'unnamed_posix'
243 elif host_system == 'linux'
244   sema_kind = 'unnamed_posix'
245   cppflags += '-D_GNU_SOURCE'
247 elif host_system == 'netbsd'
248   # We must resolve all dynamic linking in the core server at program start.
249   # Otherwise the postmaster can self-deadlock due to signals interrupting
250   # resolution of calls, since NetBSD's linker takes a lock while doing that
251   # and some postmaster signal handlers do things that will also acquire that
252   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
253   # While there's not a hard reason to adopt these settings for our other
254   # executables, there's also little reason not to, so just add them to
255   # LDFLAGS.
256   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
258 elif host_system == 'openbsd'
259   # you're ok
261 elif host_system == 'sunos'
262   portname = 'solaris'
263   export_fmt = '-Wl,-M@0@'
264   # We need these #defines to get POSIX-conforming versions
265   # of many interfaces (sigwait, getpwuid_r, shmdt, ...).
266   cppflags += [
267     '-D_POSIX_C_SOURCE=200112L',
268     '-D__EXTENSIONS__',
269     '-D_POSIX_PTHREAD_SEMANTICS',
270   ]
272 elif host_system == 'windows'
273   portname = 'win32'
274   exesuffix = '.exe'
275   dlsuffix = '.dll'
276   library_path_var = ''
277   if cc.get_id() != 'msvc'
278     # define before including <time.h> for getting localtime_r() etc. on MinGW
279     cppflags += '-D_POSIX_C_SOURCE'
280   endif
282   export_file_format = 'win'
283   export_file_suffix = 'def'
284   if cc.get_id() == 'msvc'
285     export_fmt = '/DEF:@0@'
286     mod_link_with_name = '@0@.lib'
287   else
288     export_fmt = '@0@'
289     mod_link_with_name = 'lib@0@.a'
290   endif
291   mod_link_args_fmt = ['@0@']
292   mod_link_with_dir = 'libdir'
294   shmem_kind = 'win32'
295   sema_kind = 'win32'
297   cdata.set('WIN32_STACK_RLIMIT', 4194304)
298   if cc.get_id() == 'msvc'
299     ldflags += '/INCREMENTAL:NO'
300     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
301     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
302   else
303     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
304     # Need to allow multiple definitions, we e.g. want to override getopt.
305     ldflags += '-Wl,--allow-multiple-definition'
306     # Ensure we get MSVC-like linking behavior.
307     ldflags += '-Wl,--disable-auto-import'
308   endif
310   os_deps += cc.find_library('ws2_32', required: true)
311   secur32_dep = cc.find_library('secur32', required: true)
312   backend_deps += secur32_dep
313   libpq_deps += secur32_dep
315   postgres_inc_d += 'src/include/port/win32'
316   if cc.get_id() == 'msvc'
317     postgres_inc_d += 'src/include/port/win32_msvc'
318   endif
320   windows = import('windows')
322 else
323   # XXX: Should we add an option to override the host_system as an escape
324   # hatch?
325   error('unknown host system: @0@'.format(host_system))
326 endif
330 ###############################################################
331 # Program paths
332 ###############################################################
334 # External programs
335 perl = find_program(get_option('PERL'), required: true, native: true)
336 python = find_program(get_option('PYTHON'), required: true, native: true)
337 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
338 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
339 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
340 prove = find_program(get_option('PROVE'), native: true, required: false)
341 tar = find_program(get_option('TAR'), native: true, required: false)
342 gzip = find_program(get_option('GZIP'), native: true, required: false)
343 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
344 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
345 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
346 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
347 missing = find_program('config/missing', native: true)
348 cp = find_program('cp', required: false, native: true)
349 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
350 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
352 bison_flags = []
353 if bison.found()
354   bison_version_c = run_command(bison, '--version', check: true)
355   # bison version string helpfully is something like
356   # >>bison (GNU bison) 3.8.1<<
357   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
358   if bison_version.version_compare('>=3.0')
359     bison_flags += ['-Wno-deprecated']
360   endif
361 endif
362 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
363 bison_kw = {
364   'output': ['@BASENAME@.c', '@BASENAME@.h'],
365   'command': bison_cmd,
368 flex_flags = []
369 if flex.found()
370   flex_version_c = run_command(flex, '--version', check: true)
371   flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
372 endif
373 flex_wrapper = files('src/tools/pgflex')
374 flex_cmd = [python, flex_wrapper,
375   '--builddir', '@BUILD_ROOT@',
376   '--srcdir', '@SOURCE_ROOT@',
377   '--privatedir', '@PRIVATE_DIR@',
378   '--flex', flex, '--perl', perl,
379   '-i', '@INPUT@', '-o', '@OUTPUT0@',
382 wget = find_program('wget', required: false, native: true)
383 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
385 install_files = files('src/tools/install_files')
389 ###############################################################
390 # Path to meson (for tests etc)
391 ###############################################################
393 # NB: this should really be part of meson, see
394 # https://github.com/mesonbuild/meson/issues/8511
395 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
397 if meson_binpath_r.stdout() == ''
398   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
399     meson_binpath_r.returncode(),
400     meson_binpath_r.stdout(),
401     meson_binpath_r.stderr()))
402 endif
404 meson_binpath_s = meson_binpath_r.stdout().split('\n')
405 meson_binpath_len = meson_binpath_s.length()
407 if meson_binpath_len < 1
408   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
409 endif
411 i = 0
412 meson_impl = ''
413 meson_binpath = ''
414 meson_args = []
415 foreach e : meson_binpath_s
416   if i == 0
417     meson_impl = e
418   elif i == 1
419     meson_binpath = e
420   else
421     meson_args += e
422   endif
423   i += 1
424 endforeach
426 if meson_impl not in ['muon', 'meson']
427   error('unknown meson implementation "@0@"'.format(meson_impl))
428 endif
430 meson_bin = find_program(meson_binpath, native: true)
434 ###############################################################
435 # Option Handling
436 ###############################################################
438 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
439 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
441 blocksize = get_option('blocksize').to_int() * 1024
443 if get_option('segsize_blocks') != 0
444   if get_option('segsize') != 1
445     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
446   endif
448   segsize = get_option('segsize_blocks')
449 else
450   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
451 endif
453 cdata.set('BLCKSZ', blocksize, description:
454 '''Size of a disk block --- this also limits the size of a tuple. You can set
455    it bigger if you need bigger tuples (although TOAST should reduce the need
456    to have large tuples, since fields can be spread across multiple tuples).
457    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
458    currently 2^15 (32768). This is determined by the 15-bit widths of the
459    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
460    Changing BLCKSZ requires an initdb.''')
462 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
463 cdata.set('RELSEG_SIZE', segsize)
464 cdata.set('DEF_PGPORT', get_option('pgport'))
465 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
466 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
467 if get_option('system_tzdata') != ''
468   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
469 endif
473 ###############################################################
474 # Directories
475 ###############################################################
477 # These are set by the equivalent --xxxdir configure options.  We
478 # append "postgresql" to some of them, if the string does not already
479 # contain "pgsql" or "postgres", in order to avoid directory clutter.
481 pkg = 'postgresql'
483 dir_prefix = get_option('prefix')
485 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
487 dir_bin = get_option('bindir')
489 dir_data = get_option('datadir')
490 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
491   dir_data = dir_data / pkg
492 endif
494 dir_sysconf = get_option('sysconfdir')
495 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
496   dir_sysconf = dir_sysconf / pkg
497 endif
499 dir_lib = get_option('libdir')
501 dir_lib_pkg = dir_lib
502 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
503   dir_lib_pkg = dir_lib_pkg / pkg
504 endif
506 dir_pgxs = dir_lib_pkg / 'pgxs'
508 dir_include = get_option('includedir')
510 dir_include_pkg = dir_include
511 dir_include_pkg_rel = ''
512 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
513   dir_include_pkg = dir_include_pkg / pkg
514   dir_include_pkg_rel = pkg
515 endif
517 dir_man = get_option('mandir')
519 # FIXME: These used to be separately configurable - worth adding?
520 dir_doc = get_option('datadir') / 'doc'
521 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
522   dir_doc = dir_doc / pkg
523 endif
524 dir_doc_html = dir_doc / 'html'
526 dir_locale = get_option('localedir')
529 # Derived values
530 dir_bitcode = dir_lib_pkg / 'bitcode'
531 dir_include_internal = dir_include_pkg / 'internal'
532 dir_include_server = dir_include_pkg / 'server'
533 dir_include_extension = dir_include_server / 'extension'
534 dir_data_extension = dir_data / 'extension'
535 dir_doc_extension = dir_doc / 'extension'
539 ###############################################################
540 # Search paths, preparation for compiler tests
542 # NB: Arguments added later are not automatically used for subsequent
543 # configuration-time checks (so they are more isolated). If they should be
544 # used, they need to be added to test_c_args as well.
545 ###############################################################
547 postgres_inc = [include_directories(postgres_inc_d)]
548 test_lib_d = postgres_lib_d
549 test_c_args = cppflags + cflags
553 ###############################################################
554 # Library: bsd-auth
555 ###############################################################
557 bsd_authopt = get_option('bsd_auth')
558 bsd_auth = not_found_dep
559 if cc.check_header('bsd_auth.h', required: bsd_authopt,
560     args: test_c_args, include_directories: postgres_inc)
561   cdata.set('USE_BSD_AUTH', 1)
562   bsd_auth = declare_dependency()
563 endif
567 ###############################################################
568 # Library: bonjour
570 # For now don't search for DNSServiceRegister in a library - only Apple's
571 # Bonjour implementation, which is always linked, works.
572 ###############################################################
574 bonjouropt = get_option('bonjour')
575 bonjour = not_found_dep
576 if cc.check_header('dns_sd.h', required: bonjouropt,
577     args: test_c_args, include_directories: postgres_inc) and \
578    cc.has_function('DNSServiceRegister',
579     args: test_c_args, include_directories: postgres_inc)
580   cdata.set('USE_BONJOUR', 1)
581   bonjour = declare_dependency()
582 endif
586 ###############################################################
587 # Option: docs in HTML and man page format
588 ###############################################################
590 docs_opt = get_option('docs')
591 docs_dep = not_found_dep
592 if not docs_opt.disabled()
593   if xmllint_bin.found() and xsltproc_bin.found()
594     docs_dep = declare_dependency()
595   elif docs_opt.enabled()
596     error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
597   endif
598 endif
602 ###############################################################
603 # Option: docs in PDF format
604 ###############################################################
606 docs_pdf_opt = get_option('docs_pdf')
607 docs_pdf_dep = not_found_dep
608 if not docs_pdf_opt.disabled()
609   fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
610   if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
611     docs_pdf_dep = declare_dependency()
612   elif docs_pdf_opt.enabled()
613     error('missing required tools for docs in PDF format')
614   endif
615 endif
619 ###############################################################
620 # Library: GSSAPI
621 ###############################################################
623 gssapiopt = get_option('gssapi')
624 krb_srvtab = ''
625 have_gssapi = false
626 if not gssapiopt.disabled()
627   gssapi = dependency('krb5-gssapi', required: false)
628   have_gssapi = gssapi.found()
630   if have_gssapi
631       gssapi_deps = [gssapi]
632   elif not have_gssapi
633     # Hardcoded lookup for gssapi. This is necessary as gssapi on windows does
634     # not install neither pkg-config nor cmake dependency information.
635     if host_system == 'windows'
636       is_64  = cc.sizeof('void *', args: test_c_args) == 8
637       if is_64
638         gssapi_search_libs = ['gssapi64', 'krb5_64', 'comerr64']
639       else
640         gssapi_search_libs = ['gssapi32', 'krb5_32', 'comerr32']
641       endif
642     else
643       gssapi_search_libs = ['gssapi_krb5']
644     endif
646     gssapi_deps = []
647     foreach libname : gssapi_search_libs
648       lib = cc.find_library(libname, dirs: test_lib_d, required: false)
649       if lib.found()
650         have_gssapi = true
651         gssapi_deps += lib
652       endif
653     endforeach
655     if have_gssapi
656       # Meson before 0.57.0 did not support using check_header() etc with
657       # declare_dependency(). Thus the tests below use the library looked up
658       # above.  Once we require a newer meson version, we can simplify.
659       gssapi = declare_dependency(dependencies: gssapi_deps)
660     endif
661   endif
663   if not have_gssapi
664   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi_deps, required: false,
665       args: test_c_args, include_directories: postgres_inc)
666     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
667   elif cc.check_header('gssapi.h', dependencies: gssapi_deps, required: gssapiopt,
668       args: test_c_args, include_directories: postgres_inc)
669     cdata.set('HAVE_GSSAPI_H', 1)
670   else
671     have_gssapi = false
672   endif
674   if not have_gssapi
675   elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi_deps, required: false,
676       args: test_c_args, include_directories: postgres_inc)
677     cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
678   elif cc.check_header('gssapi_ext.h', dependencies: gssapi_deps, required: gssapiopt,
679       args: test_c_args, include_directories: postgres_inc)
680     cdata.set('HAVE_GSSAPI_EXT_H', 1)
681   else
682     have_gssapi = false
683   endif
685   if not have_gssapi
686   elif cc.has_function('gss_store_cred_into', dependencies: gssapi_deps,
687       args: test_c_args, include_directories: postgres_inc)
688     cdata.set('ENABLE_GSS', 1)
690     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
691     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
692   elif gssapiopt.enabled()
693     error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
694   else
695     have_gssapi = false
696   endif
698   if not have_gssapi and gssapiopt.enabled()
699     error('dependency lookup for gssapi failed')
700   endif
702 endif
703 if not have_gssapi
704   gssapi = not_found_dep
705 endif
709 ###############################################################
710 # Library: ldap
711 ###############################################################
713 ldapopt = get_option('ldap')
714 if ldapopt.disabled()
715   ldap = not_found_dep
716   ldap_r = not_found_dep
717 elif host_system == 'windows'
718   ldap = cc.find_library('wldap32', required: ldapopt)
719   ldap_r = ldap
720 else
721   # macos framework dependency is buggy for ldap (one can argue whether it's
722   # Apple's or meson's fault), leading to an endless recursion with ldap.h
723   # including itself. See https://github.com/mesonbuild/meson/issues/10002
724   # Luckily we only need pkg-config support, so the workaround isn't
725   # complicated.
726   ldap = dependency('ldap', method: 'pkg-config', required: false)
727   ldap_r = ldap
729   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
730   # installed
731   if not ldap.found()
732     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
733       has_headers: 'ldap.h', header_include_directories: postgres_inc)
735     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
736     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
737     # library from a separate OpenLDAP installation).  The most reliable
738     # way to check that is to check for a function introduced in 2.5.
739     if not ldap.found()
740       # don't have ldap, we shouldn't check for ldap_r
741     elif cc.has_function('ldap_verify_credentials',
742         dependencies: ldap, args: test_c_args)
743       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
744     else
746       # Use ldap_r for FE if available, else assume ldap is thread-safe.
747       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
748         has_headers: 'ldap.h', header_include_directories: postgres_inc)
749       if not ldap_r.found()
750         ldap_r = ldap
751       else
752         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
753         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
754       endif
756       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
757       # process.  Check for OpenLDAP versions known not to tolerate doing so;
758       # assume non-OpenLDAP implementations are safe.  The dblink test suite
759       # exercises the hazardous interaction directly.
760       compat_test_code = '''
761 #include <ldap.h>
762 #if !defined(LDAP_VENDOR_VERSION) || \
763      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
764       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
765 choke me
766 #endif
768       if not cc.compiles(compat_test_code,
769           name: 'LDAP implementation compatible',
770           dependencies: ldap, args: test_c_args)
771         warning('''
772 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
773 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
774 *** also uses LDAP will crash on exit.''')
775       endif
776     endif
777   endif
779   if ldap.found() and cc.has_function('ldap_initialize',
780       dependencies: ldap, args: test_c_args)
781     cdata.set('HAVE_LDAP_INITIALIZE', 1)
782   endif
783 endif
785 if ldap.found()
786   assert(ldap_r.found())
787   cdata.set('USE_LDAP', 1)
788 else
789   assert(not ldap_r.found())
790 endif
794 ###############################################################
795 # Library: LLVM
796 ###############################################################
798 llvmopt = get_option('llvm')
799 llvm = not_found_dep
800 if add_languages('cpp', required: llvmopt, native: false)
801   llvm = dependency('llvm', version: '>=14', method: 'config-tool', required: llvmopt)
803   if llvm.found()
805     cdata.set('USE_LLVM', 1)
807     cpp = meson.get_compiler('cpp')
809     llvm_binpath = llvm.get_variable(configtool: 'bindir')
811     ccache = find_program('ccache', native: true, required: false)
813     # Some distros put LLVM and clang in different paths, so fallback to
814     # find via PATH, too.
815     clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
816   endif
817 elif llvmopt.auto()
818   message('llvm requires a C++ compiler')
819 endif
823 ###############################################################
824 # Library: icu
825 ###############################################################
827 icuopt = get_option('icu')
828 if not icuopt.disabled()
829   icu = dependency('icu-uc', required: false)
830   if icu.found()
831     icu_i18n = dependency('icu-i18n', required: true)
832   endif
834   # Unfortunately the dependency is named differently with cmake
835   if not icu.found() # combine with above once meson 0.60.0 is required
836     icu = dependency('ICU', required: icuopt,
837                      components: ['uc'], modules: ['ICU::uc'], method: 'cmake')
838     if icu.found()
839       icu_i18n = dependency('ICU', required: true,
840                             components: ['i18n'], modules: ['ICU::i18n'])
841     endif
842   endif
844   if icu.found()
845     cdata.set('USE_ICU', 1)
846   else
847     icu_i18n = not_found_dep
848   endif
850 else
851   icu = not_found_dep
852   icu_i18n = not_found_dep
853 endif
857 ###############################################################
858 # Library: libxml
859 ###############################################################
861 libxmlopt = get_option('libxml')
862 if not libxmlopt.disabled()
863   libxml = dependency('libxml-2.0', required: false, version: '>= 2.6.23')
864   # Unfortunately the dependency is named differently with cmake
865   if not libxml.found() # combine with above once meson 0.60.0 is required
866     libxml = dependency('LibXml2', required: libxmlopt, version: '>= 2.6.23',
867       method: 'cmake')
868   endif
870   if libxml.found()
871     cdata.set('USE_LIBXML', 1)
872   endif
873 else
874   libxml = not_found_dep
875 endif
879 ###############################################################
880 # Library: libxslt
881 ###############################################################
883 libxsltopt = get_option('libxslt')
884 if not libxsltopt.disabled()
885   libxslt = dependency('libxslt', required: false)
886   # Unfortunately the dependency is named differently with cmake
887   if not libxslt.found() # combine with above once meson 0.60.0 is required
888     libxslt = dependency('LibXslt', required: libxsltopt, method: 'cmake')
889   endif
891   if libxslt.found()
892     cdata.set('USE_LIBXSLT', 1)
893   endif
894 else
895   libxslt = not_found_dep
896 endif
900 ###############################################################
901 # Library: lz4
902 ###############################################################
904 lz4opt = get_option('lz4')
905 if not lz4opt.disabled()
906   lz4 = dependency('liblz4', required: false)
907   # Unfortunately the dependency is named differently with cmake
908   if not lz4.found() # combine with above once meson 0.60.0 is required
909     lz4 = dependency('lz4', required: lz4opt,
910                      method: 'cmake', modules: ['LZ4::lz4_shared'],
911                     )
912   endif
914   if lz4.found()
915     cdata.set('USE_LZ4', 1)
916     cdata.set('HAVE_LIBLZ4', 1)
917   endif
919 else
920   lz4 = not_found_dep
921 endif
925 ###############################################################
926 # Library: Tcl (for pltcl)
928 # NB: tclConfig.sh is used in autoconf build for getting
929 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
930 # variables. For now we have not seen a need to copy
931 # that behaviour to the meson build.
932 ###############################################################
934 tclopt = get_option('pltcl')
935 tcl_version = get_option('tcl_version')
936 tcl_dep = not_found_dep
937 if not tclopt.disabled()
939   # via pkg-config
940   tcl_dep = dependency(tcl_version, required: false)
942   if not tcl_dep.found()
943     tcl_dep = cc.find_library(tcl_version,
944       required: tclopt,
945       dirs: test_lib_d)
946   endif
948   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
949     tcl_dep = not_found_dep
950   endif
951 endif
955 ###############################################################
956 # Library: pam
957 ###############################################################
959 pamopt = get_option('pam')
960 if not pamopt.disabled()
961   pam = dependency('pam', required: false)
963   if not pam.found()
964     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
965   endif
967   if pam.found()
968     pam_header_found = false
970     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
971     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
972         args: test_c_args, include_directories: postgres_inc)
973       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
974       pam_header_found = true
975     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
976         args: test_c_args, include_directories: postgres_inc)
977       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
978       pam_header_found = true
979     endif
981     if pam_header_found
982       cdata.set('USE_PAM', 1)
983     else
984       pam = not_found_dep
985     endif
986   endif
987 else
988   pam = not_found_dep
989 endif
993 ###############################################################
994 # Library: Perl (for plperl)
995 ###############################################################
997 perlopt = get_option('plperl')
998 perl_dep = not_found_dep
999 if not perlopt.disabled()
1000   perl_may_work = true
1002   # First verify that perl has the necessary dependencies installed
1003   perl_mods = run_command(
1004     [perl,
1005      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
1006      '-e', ''],
1007     check: false)
1008   if perl_mods.returncode() != 0
1009     perl_may_work = false
1010     perl_msg = 'perl installation does not have the required modules'
1011   endif
1013   # Then inquire perl about its configuration
1014   if perl_may_work
1015     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
1016     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
1017     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
1018     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
1019     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
1021     perl_inc_dir = '@0@/CORE'.format(archlibexp)
1023     if perlversion.version_compare('< 5.14')
1024       perl_may_work = false
1025       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
1026     elif useshrplib != 'true'
1027       perl_may_work = false
1028       perl_msg = 'need a shared perl'
1029     endif
1030   endif
1032   if perl_may_work
1033     # On most platforms, archlibexp is also where the Perl include files live ...
1034     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
1035     # ... but on newer macOS versions, we must use -iwithsysroot to look
1036     # under sysroot
1037     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
1038        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
1039       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
1040     endif
1042     # check compiler finds header
1043     if not cc.has_header('perl.h', required: false,
1044         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
1045       perl_may_work = false
1046       perl_msg = 'missing perl.h'
1047     endif
1048   endif
1050   if perl_may_work
1051     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
1053     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
1054     foreach flag : perl_ccflags_r.split(' ')
1055       if flag.startswith('-D') and \
1056           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
1057         perl_ccflags += flag
1058       endif
1059     endforeach
1061     if host_system == 'windows'
1062       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
1064       if cc.get_id() == 'msvc'
1065         # prevent binary mismatch between MSVC built plperl and Strawberry or
1066         # msys ucrt perl libraries
1067         perl_v = run_command(perl, '-V').stdout()
1068         if not perl_v.contains('USE_THREAD_SAFE_LOCALE')
1069           perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
1070         endif
1071       endif
1072     endif
1074     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
1075     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
1077     # We are after Embed's ldopts, but without the subset mentioned in
1078     # Config's ccdlflags and ldflags.  (Those are the choices of those who
1079     # built the Perl installation, which are not necessarily appropriate
1080     # for building PostgreSQL.)
1081     perl_ldopts = run_command(perl, '-e', '''
1082 use ExtUtils::Embed;
1083 use Text::ParseWords;
1084 # tell perl to suppress including these in ldopts
1085 *ExtUtils::Embed::_ldflags =*ExtUtils::Embed::_ccdlflags = sub { return ""; };
1086 # adding an argument to ldopts makes it return a value instead of printing
1087 # print one of these per line so splitting will preserve spaces in file names.
1088 # shellwords eats backslashes, so we need to escape them.
1089 (my $opts = ldopts(undef)) =~ s!\\!\\\\!g;
1090 print "$_\n" foreach shellwords($opts);
1091 ''',
1092      check: true).stdout().strip().split('\n')
1094     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1096     perl_dep_int = declare_dependency(
1097       compile_args: perl_ccflags,
1098       link_args: perl_ldopts,
1099       version: perlversion,
1100     )
1102     # While we're at it, check that we can link to libperl.
1103     # On most platforms, if perl.h is there then libperl.so will be too, but
1104     # at this writing Debian packages them separately.
1105     perl_link_test = '''
1106 /* see plperl.h */
1107 #ifdef _MSC_VER
1108 #define __inline__ inline
1109 #endif
1110 #include <EXTERN.h>
1111 #include <perl.h>
1112 int main(void)
1114 perl_alloc();
1115 }'''
1116     if not cc.links(perl_link_test, name: 'libperl',
1117           args: test_c_args + perl_ccflags + perl_ldopts,
1118           include_directories: postgres_inc)
1119       perl_may_work = false
1120       perl_msg = 'missing libperl'
1121     endif
1123   endif # perl_may_work
1125   if perl_may_work
1126     perl_dep = perl_dep_int
1127   else
1128     if perlopt.enabled()
1129       error('dependency plperl failed: @0@'.format(perl_msg))
1130     else
1131       message('disabling optional dependency plperl: @0@'.format(perl_msg))
1132     endif
1133   endif
1134 endif
1138 ###############################################################
1139 # Library: Python (for plpython)
1140 ###############################################################
1142 pyopt = get_option('plpython')
1143 python3_dep = not_found_dep
1144 if not pyopt.disabled()
1145   pm = import('python')
1146   python3_inst = pm.find_installation(python.path(), required: pyopt)
1147   if python3_inst.found()
1148     python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1149     # Remove this check after we depend on Meson >= 1.1.0
1150     if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1151       python3_dep = not_found_dep
1152     endif
1153   endif
1154 endif
1158 ###############################################################
1159 # Library: Readline
1160 ###############################################################
1162 if not get_option('readline').disabled()
1163   libedit_preferred = get_option('libedit_preferred')
1164   # Set the order of readline dependencies.
1165   # cc.find_library breaks and throws on the first dependency which
1166   # is marked as required=true and can't be found. Thus, we only mark
1167   # the last dependency to look up as required, to not throw too early.
1168   check_readline_deps = [
1169     {
1170       'name': libedit_preferred ? 'libedit' : 'readline',
1171       'required': false
1172     },
1173     {
1174       'name': libedit_preferred ? 'readline' : 'libedit',
1175       'required': get_option('readline')
1176     }
1177   ]
1179   foreach readline_dep : check_readline_deps
1180     readline = dependency(readline_dep['name'], required: false)
1181     if not readline.found()
1182       readline = cc.find_library(readline_dep['name'],
1183         required: readline_dep['required'],
1184         dirs: test_lib_d)
1185     endif
1186     if readline.found()
1187       break
1188     endif
1189   endforeach
1191   if readline.found()
1192     cdata.set('HAVE_LIBREADLINE', 1)
1194     editline_prefix = {
1195       'header_prefix': 'editline/',
1196       'flag_prefix': 'EDITLINE_',
1197     }
1198     readline_prefix = {
1199       'header_prefix': 'readline/',
1200       'flag_prefix': 'READLINE_',
1201     }
1202     default_prefix = {
1203       'header_prefix': '',
1204       'flag_prefix': '',
1205     }
1207     # Set the order of prefixes
1208     prefixes = libedit_preferred ? \
1209       [editline_prefix, default_prefix, readline_prefix] : \
1210       [readline_prefix, default_prefix, editline_prefix]
1212     at_least_one_header_found = false
1213     foreach header : ['history', 'readline']
1214       is_found = false
1215       foreach prefix : prefixes
1216         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1217         # Check history.h and readline.h
1218         if not is_found and cc.has_header(header_file,
1219             args: test_c_args, include_directories: postgres_inc,
1220             dependencies: [readline], required: false)
1221           if header == 'readline'
1222             readline_h = header_file
1223           endif
1224           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1225           is_found = true
1226           at_least_one_header_found = true
1227         endif
1228       endforeach
1229     endforeach
1231     if not at_least_one_header_found
1232       error('''readline header not found
1233 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1234 failure. It is possible the compiler isn't looking in the proper directory.
1235 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1236     endif
1238     check_funcs = [
1239       'append_history',
1240       'history_truncate_file',
1241       'rl_completion_matches',
1242       'rl_filename_completion_function',
1243       'rl_reset_screen_size',
1244       'rl_variable_bind',
1245     ]
1247     foreach func : check_funcs
1248       found = cc.has_function(func, dependencies: [readline],
1249         args: test_c_args, include_directories: postgres_inc)
1250       cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1251     endforeach
1253     check_vars = [
1254       'rl_completion_suppress_quote',
1255       'rl_filename_quote_characters',
1256       'rl_filename_quoting_function',
1257     ]
1259     foreach var : check_vars
1260       cdata.set('HAVE_' + var.to_upper(),
1261         cc.has_header_symbol(readline_h, var,
1262           args: test_c_args, include_directories: postgres_inc,
1263           prefix: '#include <stdio.h>',
1264           dependencies: [readline]) ? 1 : false)
1265     endforeach
1267     # If found via cc.find_library() ensure headers are found when using the
1268     # dependency. On meson < 0.57 one cannot do compiler checks using the
1269     # dependency returned by declare_dependency(), so we can't do this above.
1270     if readline.type_name() == 'library'
1271       readline = declare_dependency(dependencies: readline,
1272         include_directories: postgres_inc)
1273     endif
1275     # On windows with mingw readline requires auto-import to successfully
1276     # link, as the headers don't use declspec(dllimport)
1277     if host_system == 'windows' and cc.get_id() != 'msvc'
1278       readline = declare_dependency(dependencies: readline,
1279         link_args: '-Wl,--enable-auto-import')
1280     endif
1281   endif
1283   # XXX: Figure out whether to implement mingw warning equivalent
1284 else
1285   readline = not_found_dep
1286 endif
1290 ###############################################################
1291 # Library: selinux
1292 ###############################################################
1294 selinux = not_found_dep
1295 selinuxopt = get_option('selinux')
1296 if meson.version().version_compare('>=0.59')
1297   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1298 endif
1299 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1300 cdata.set('HAVE_LIBSELINUX',
1301   selinux.found() ? 1 : false)
1305 ###############################################################
1306 # Library: systemd
1307 ###############################################################
1309 systemd = not_found_dep
1310 systemdopt = get_option('systemd')
1311 if meson.version().version_compare('>=0.59')
1312   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1313 endif
1314 systemd = dependency('libsystemd', required: systemdopt)
1315 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1319 ###############################################################
1320 # Library: SSL
1321 ###############################################################
1323 ssl = not_found_dep
1324 ssl_library = 'none'
1325 sslopt = get_option('ssl')
1327 if sslopt == 'auto' and auto_features.disabled()
1328   sslopt = 'none'
1329 endif
1331 if sslopt in ['auto', 'openssl']
1332   openssl_required = (sslopt == 'openssl')
1334   # Try to find openssl via pkg-config et al, if that doesn't work
1335   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1336   # the library names that we know about.
1338   # via pkg-config et al
1339   ssl = dependency('openssl', required: false)
1340   # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1341   # we pass cc.find_library() results if necessary
1342   ssl_int = []
1344   # via library + headers
1345   if not ssl.found()
1346     ssl_lib = cc.find_library('ssl',
1347       dirs: test_lib_d,
1348       header_include_directories: postgres_inc,
1349       has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1350       required: openssl_required)
1351     crypto_lib = cc.find_library('crypto',
1352       dirs: test_lib_d,
1353       required: openssl_required)
1354     if ssl_lib.found() and crypto_lib.found()
1355       ssl_int = [ssl_lib, crypto_lib]
1356       ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1357     endif
1358   elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1359        cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1360     ssl_int = [ssl]
1361   else
1362     ssl = not_found_dep
1363   endif
1365   if ssl.found()
1366     check_funcs = [
1367       ['CRYPTO_new_ex_data', {'required': true}],
1368       ['SSL_new', {'required': true}],
1370       # Functions introduced in OpenSSL 1.1.1.
1371       ['SSL_CTX_set_ciphersuites', {'required': true}],
1373       # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1374       ['SSL_CTX_set_cert_cb'],
1376       # Function introduced in OpenSSL 1.1.1, not in LibreSSL.
1377       ['X509_get_signature_info'],
1378       ['SSL_CTX_set_num_tickets'],
1379     ]
1381     are_openssl_funcs_complete = true
1382     foreach c : check_funcs
1383       func = c.get(0)
1384       val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1385       required = c.get(1, {}).get('required', false)
1386       if required and not val
1387         are_openssl_funcs_complete = false
1388         if openssl_required
1389           error('openssl function @0@ is required'.format(func))
1390         endif
1391         break
1392       elif not required
1393         cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1394       endif
1395     endforeach
1397     if are_openssl_funcs_complete
1398       cdata.set('USE_OPENSSL', 1,
1399                 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1400       cdata.set('OPENSSL_API_COMPAT', '0x10101000L',
1401                 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1402       ssl_library = 'openssl'
1403     else
1404       ssl = not_found_dep
1405     endif
1406   endif
1407 endif
1409 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1410   error('no SSL library found')
1411 endif
1415 ###############################################################
1416 # Library: uuid
1417 ###############################################################
1419 uuidopt = get_option('uuid')
1420 if uuidopt != 'none'
1421   uuidname = uuidopt.to_upper()
1422   if uuidopt == 'e2fs'
1423     uuid = dependency('uuid', required: true)
1424     uuidfunc = 'uuid_generate'
1425     uuidheader = 'uuid/uuid.h'
1426   elif uuidopt == 'bsd'
1427     # libc should have uuid function
1428     uuid = declare_dependency()
1429     uuidfunc = 'uuid_to_string'
1430     uuidheader = 'uuid.h'
1431   elif uuidopt == 'ossp'
1432     # In upstream, the package and library is called just 'uuid', but many
1433     # distros change it to 'ossp-uuid'.
1434     uuid = dependency('ossp-uuid', 'uuid', required: false)
1435     uuidfunc = 'uuid_export'
1436     uuidheader = 'uuid.h'
1438     # Hardcoded lookup for ossp-uuid. This is necessary as ossp-uuid on
1439     # windows installs neither a pkg-config nor a cmake dependency
1440     # information. Nor is there another supported uuid implementation
1441     # available on windows.
1442     if not uuid.found()
1443       uuid = cc.find_library('ossp-uuid',
1444         required: false, dirs: test_lib_d,
1445         has_headers: uuidheader, header_include_directories: postgres_inc)
1446     endif
1447     if not uuid.found()
1448       uuid = cc.find_library('uuid',
1449         required: true, dirs: test_lib_d,
1450         has_headers: uuidheader, header_include_directories: postgres_inc)
1451     endif
1452   else
1453     error('unknown uuid build option value: @0@'.format(uuidopt))
1454   endif
1456   if not cc.has_header_symbol(uuidheader, uuidfunc,
1457                               args: test_c_args,
1458                               include_directories: postgres_inc,
1459                               dependencies: uuid)
1460     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1461   endif
1462   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1464   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1465            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1466 else
1467   uuid = not_found_dep
1468 endif
1472 ###############################################################
1473 # Library: zlib
1474 ###############################################################
1476 zlibopt = get_option('zlib')
1477 zlib = not_found_dep
1478 if not zlibopt.disabled()
1479   zlib_t = dependency('zlib', required: zlibopt)
1481   if zlib_t.type_name() == 'internal'
1482     # if fallback was used, we don't need to test if headers are present (they
1483     # aren't built yet, so we can't test)
1484     zlib = zlib_t
1485   elif not zlib_t.found()
1486     warning('did not find zlib')
1487   elif not cc.has_header('zlib.h',
1488       args: test_c_args, include_directories: postgres_inc,
1489       dependencies: [zlib_t], required: zlibopt)
1490     warning('zlib header not found')
1491   else
1492     zlib = zlib_t
1493   endif
1495   if zlib.found()
1496     cdata.set('HAVE_LIBZ', 1)
1497   endif
1498 endif
1502 ###############################################################
1503 # Library: tap test dependencies
1504 ###############################################################
1506 # Check whether tap tests are enabled or not
1507 tap_tests_enabled = false
1508 tapopt = get_option('tap_tests')
1509 if not tapopt.disabled()
1510   # Checking for perl modules for tap tests
1511   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1512   if perl_ipc_run_check.returncode() != 0
1513     message(perl_ipc_run_check.stderr().strip())
1514     if tapopt.enabled()
1515       error('Additional Perl modules are required to run TAP tests.')
1516     else
1517       warning('Additional Perl modules are required to run TAP tests.')
1518     endif
1519   else
1520     tap_tests_enabled = true
1521   endif
1522 endif
1526 ###############################################################
1527 # Library: zstd
1528 ###############################################################
1530 zstdopt = get_option('zstd')
1531 if not zstdopt.disabled()
1532   zstd = dependency('libzstd', required: false, version: '>=1.4.0')
1533   # Unfortunately the dependency is named differently with cmake
1534   if not zstd.found() # combine with above once meson 0.60.0 is required
1535     zstd = dependency('zstd', required: zstdopt, version: '>=1.4.0',
1536                       method: 'cmake', modules: ['zstd::libzstd_shared'])
1537   endif
1539   if zstd.found()
1540     cdata.set('USE_ZSTD', 1)
1541     cdata.set('HAVE_LIBZSTD', 1)
1542   endif
1544 else
1545   zstd = not_found_dep
1546 endif
1550 ###############################################################
1551 # Compiler tests
1552 ###############################################################
1554 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1555 # unnecessarily, because we optionally rely on newer features.
1556 c99_test = '''
1557 #include <stdbool.h>
1558 #include <complex.h>
1559 #include <tgmath.h>
1560 #include <inttypes.h>
1562 struct named_init_test {
1563   int a;
1564   int b;
1567 extern void structfunc(struct named_init_test);
1569 int main(int argc, char **argv)
1571   struct named_init_test nit = {
1572     .a = 3,
1573     .b = 5,
1574   };
1576   for (int loop_var = 0; loop_var < 3; loop_var++)
1577   {
1578     nit.a += nit.b;
1579   }
1581   structfunc((struct named_init_test){1, 0});
1583   return nit.a != 0;
1587 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1588   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1589         args: test_c_args + ['-std=c99'])
1590     test_c_args += '-std=c99'
1591     cflags += '-std=c99'
1592   else
1593     error('C compiler does not support C99')
1594   endif
1595 endif
1597 if host_machine.endian() == 'big'
1598   cdata.set('WORDS_BIGENDIAN', 1)
1599 endif
1601 # Determine memory alignment requirements for the basic C data types.
1603 alignof_types = ['short', 'int', 'long', 'double']
1604 foreach t : alignof_types
1605   align = cc.alignment(t, args: test_c_args)
1606   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1607 endforeach
1609 # Compute maximum alignment of any basic type.
1611 # We require 'double' to have the strictest alignment among the basic types,
1612 # because otherwise the C ABI might impose 8-byte alignment on some of the
1613 # other C types that correspond to TYPALIGN_DOUBLE SQL types.  That could
1614 # cause a mismatch between the tuple layout and the C struct layout of a
1615 # catalog tuple.  We used to carefully order catalog columns such that any
1616 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1617 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1618 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1620 # We assume without checking that int64_t's alignment is at least as strong
1621 # as long, char, short, or int.  Note that we intentionally do not consider
1622 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1623 # would be too much of a penalty for disk and memory space.
1624 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1625 if cc.alignment('int64_t', args: test_c_args, prefix: '#include <stdint.h>') > alignof_double
1626   error('alignment of int64_t is greater than the alignment of double')
1627 endif
1628 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1630 cdata.set('SIZEOF_LONG', cc.sizeof('long', args: test_c_args))
1631 cdata.set('SIZEOF_LONG_LONG', cc.sizeof('long long', args: test_c_args))
1632 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1633 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1636 # Check if __int128 is a working 128 bit integer type, and if so
1637 # define PG_INT128_TYPE to that typename.
1639 # This currently only detects a GCC/clang extension, but support for other
1640 # environments may be added in the future.
1642 # For the moment we only test for support for 128bit math; support for
1643 # 128bit literals and snprintf is not required.
1644 if cc.links('''
1645   /*
1646    * We don't actually run this test, just link it to verify that any support
1647    * functions needed for __int128 are present.
1648    *
1649    * These are globals to discourage the compiler from folding all the
1650    * arithmetic tests down to compile-time constants.  We do not have
1651    * convenient support for 128bit literals at this point...
1652    */
1653   __int128 a = 48828125;
1654   __int128 b = 97656250;
1656   int main(void)
1657   {
1658       __int128 c,d;
1659       a = (a << 12) + 1; /* 200000000001 */
1660       b = (b << 12) + 5; /* 400000000005 */
1661       /* try the most relevant arithmetic ops */
1662       c = a * b;
1663       d = (c + b) / b;
1664       /* must use the results, else compiler may optimize arithmetic away */
1665       return d != a+1;
1666   }''',
1667   name: '__int128',
1668   args: test_c_args)
1670   buggy_int128 = false
1672   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1673   # If not cross-compiling, we can test for bugs and disable use of __int128
1674   # with buggy compilers.  If cross-compiling, hope for the best.
1675   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1676   if not meson.is_cross_build()
1677     r = cc.run('''
1678     /* This must match the corresponding code in c.h: */
1679     #if defined(__GNUC__) || defined(__SUNPRO_C)
1680     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1681     #elif defined(_MSC_VER)
1682     #define pg_attribute_aligned(a) __declspec(align(a))
1683     #endif
1684     typedef __int128 int128a
1685     #if defined(pg_attribute_aligned)
1686     pg_attribute_aligned(8)
1687     #endif
1688     ;
1690     int128a holder;
1691     void pass_by_val(void *buffer, int128a par) { holder = par; }
1693     int main(void)
1694     {
1695         long int i64 = 97656225L << 12;
1696         int128a q;
1697         pass_by_val(main, (int128a) i64);
1698         q = (int128a) i64;
1699         return q != holder;
1700     }''',
1701     name: '__int128 alignment bug',
1702     args: test_c_args)
1703     assert(r.compiled())
1704     if r.returncode() != 0
1705       buggy_int128 = true
1706       message('__int128 support present but buggy and thus disabled')
1707     endif
1708   endif
1710   if not buggy_int128
1711     cdata.set('PG_INT128_TYPE', '__int128')
1712     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1713   endif
1714 endif
1717 # Check if the C compiler knows computed gotos (gcc extension, also
1718 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1720 # Checking whether computed gotos are supported syntax-wise ought to
1721 # be enough, as the syntax is otherwise illegal.
1722 if cc.compiles('''
1723     static inline int foo(void)
1724     {
1725       void *labeladdrs[] = {&&my_label};
1726       goto *labeladdrs[0];
1727       my_label:
1728       return 1;
1729     }''',
1730     name: 'computed goto',
1731     args: test_c_args)
1732   cdata.set('HAVE_COMPUTED_GOTO', 1)
1733 endif
1736 # Check if the C compiler understands _Static_assert(),
1737 # and define HAVE__STATIC_ASSERT if so.
1739 # We actually check the syntax ({ _Static_assert(...) }), because we need
1740 # gcc-style compound expressions to be able to wrap the thing into macros.
1741 if cc.compiles('''
1742     int main(int arg, char **argv)
1743     {
1744         ({ _Static_assert(1, "foo"); });
1745     }
1746     ''',
1747     name: '_Static_assert',
1748     args: test_c_args)
1749   cdata.set('HAVE__STATIC_ASSERT', 1)
1750 endif
1753 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1754 # warning for each use of %m.
1755 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1756 testsrc = '''
1757 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1758 static void call_log(void)
1760     emit_log(0, "error: %s: %m", "foo");
1763 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1764 foreach a : printf_attributes
1765   if cc.compiles(testsrc.format(a),
1766       args: test_c_args + attrib_error_args, name: 'format ' + a)
1767     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1768     break
1769   endif
1770 endforeach
1773 if cc.has_function_attribute('visibility:default') and \
1774     cc.has_function_attribute('visibility:hidden')
1775   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1777   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1778   # inlineshidden to C code as well... And either way, we want to put these
1779   # flags into exported files (pgxs, .pc files).
1780   cflags_mod += '-fvisibility=hidden'
1781   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1782   ldflags_mod += '-fvisibility=hidden'
1783 endif
1786 # Check if various builtins exist. Some builtins are tested separately,
1787 # because we want to test something more complicated than the generic case.
1788 builtins = [
1789   'bswap16',
1790   'bswap32',
1791   'bswap64',
1792   'clz',
1793   'ctz',
1794   'constant_p',
1795   'frame_address',
1796   'popcount',
1797   'unreachable',
1800 foreach builtin : builtins
1801   fname = '__builtin_@0@'.format(builtin)
1802   if cc.has_function(fname, args: test_c_args)
1803     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1804   endif
1805 endforeach
1808 # Check if the C compiler understands __builtin_types_compatible_p,
1809 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1811 # We check usage with __typeof__, though it's unlikely any compiler would
1812 # have the former and not the latter.
1813 if cc.compiles('''
1814     static int x;
1815     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1816     ''',
1817     name: '__builtin_types_compatible_p',
1818     args: test_c_args)
1819   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1820 endif
1823 # Check if the C compiler understands __builtin_$op_overflow(),
1824 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1826 # Check for the most complicated case, 64 bit multiplication, as a
1827 # proxy for all of the operations.  To detect the case where the compiler
1828 # knows the function but library support is missing, we must link not just
1829 # compile, and store the results in global variables so the compiler doesn't
1830 # optimize away the call.
1831 if cc.links('''
1832     #include <stdint.h>
1833     int64_t a = 1;
1834     int64_t b = 1;
1835     int64_t result;
1837     int main(void)
1838     {
1839         return __builtin_mul_overflow(a, b, &result);
1840     }''',
1841     name: '__builtin_mul_overflow',
1842     args: test_c_args)
1843   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1844 endif
1847 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1848 # here. To prevent problems due to two detection methods working, stop
1849 # checking after one.
1850 if cc.links('''
1851     #include <cpuid.h>
1852     int main(int arg, char **argv)
1853     {
1854         unsigned int exx[4] = {0, 0, 0, 0};
1855         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1856     }
1857     ''', name: '__get_cpuid',
1858     args: test_c_args)
1859   cdata.set('HAVE__GET_CPUID', 1)
1860 elif cc.links('''
1861     #include <intrin.h>
1862     int main(int arg, char **argv)
1863     {
1864         unsigned int exx[4] = {0, 0, 0, 0};
1865         __cpuid(exx, 1);
1866     }
1867     ''', name: '__cpuid',
1868     args: test_c_args)
1869   cdata.set('HAVE__CPUID', 1)
1870 endif
1873 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1874 if cc.links('''
1875     #include <cpuid.h>
1876     int main(int arg, char **argv)
1877     {
1878         unsigned int exx[4] = {0, 0, 0, 0};
1879         __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1880     }
1881     ''', name: '__get_cpuid_count',
1882     args: test_c_args)
1883   cdata.set('HAVE__GET_CPUID_COUNT', 1)
1884 elif cc.links('''
1885     #include <intrin.h>
1886     int main(int arg, char **argv)
1887     {
1888         unsigned int exx[4] = {0, 0, 0, 0};
1889         __cpuidex(exx, 7, 0);
1890     }
1891     ''', name: '__cpuidex',
1892     args: test_c_args)
1893   cdata.set('HAVE__CPUIDEX', 1)
1894 endif
1897 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1898 # versions of clang do not understand -fexcess-precision=standard, the use of
1899 # x87 floating point operations leads to problems like isinf possibly returning
1900 # false for a value that is infinite when converted from the 80bit register to
1901 # the 8byte memory representation.
1903 # Only perform the test if the compiler doesn't understand
1904 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1905 # automatically.
1906 if '-fexcess-precision=standard' not in cflags
1907   if not cc.compiles('''
1908 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1909 choke me
1910 #endif''',
1911       name: '', args: test_c_args)
1912     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1913   endif
1914 endif
1918 ###############################################################
1919 # Compiler flags
1920 ###############################################################
1922 common_functional_flags = [
1923   # Disable strict-aliasing rules; needed for gcc 3.3+
1924   '-fno-strict-aliasing',
1925   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1926   '-fwrapv',
1927   '-fexcess-precision=standard',
1930 cflags += cc.get_supported_arguments(common_functional_flags)
1931 if llvm.found()
1932   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1933 endif
1935 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1936 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1938 common_warning_flags = [
1939   '-Wmissing-prototypes',
1940   '-Wpointer-arith',
1941   # Really don't want VLAs to be used in our dialect of C
1942   '-Werror=vla',
1943   # On macOS, complain about usage of symbols newer than the deployment target
1944   '-Werror=unguarded-availability-new',
1945   '-Wendif-labels',
1946   '-Wmissing-format-attribute',
1947   '-Wimplicit-fallthrough=3',
1948   '-Wcast-function-type',
1949   '-Wshadow=compatible-local',
1950   # This was included in -Wall/-Wformat in older GCC versions
1951   '-Wformat-security',
1954 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1955 if llvm.found()
1956   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1957 endif
1959 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1960 # the result for them
1961 cflags_no_decl_after_statement = []
1962 if cc.has_argument('-Wdeclaration-after-statement')
1963   cflags_warn += '-Wdeclaration-after-statement'
1964   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1965 endif
1967 # Some code is not clean for -Wmissing-variable-declarations, so we
1968 # make the "no" option available.  Also, while clang supports this
1969 # option for C++, gcc does not, so for consistency, leave it off for
1970 # C++.
1971 cflags_no_missing_var_decls = []
1972 if cc.has_argument('-Wmissing-variable-declarations')
1973   cflags_warn += '-Wmissing-variable-declarations'
1974   cflags_no_missing_var_decls += '-Wno-missing-variable-declarations'
1975 endif
1978 # The following tests want to suppress various unhelpful warnings by adding
1979 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1980 # switches, so we have to test for the positive form and if that works,
1981 # add the negative form.
1983 negative_warning_flags = [
1984   # Suppress clang's unhelpful unused-command-line-argument warnings.
1985   'unused-command-line-argument',
1987   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1988   # of warnings when building plperl because of usages in the Perl headers.
1989   'compound-token-split-by-macro',
1991   # Similarly disable useless truncation warnings from gcc 8+
1992   'format-truncation',
1993   'stringop-truncation',
1995   # Suppress clang 16's strict warnings about function casts
1996   'cast-function-type-strict',
1998   # To make warning_level=2 / -Wextra work, we'd need at least the following
1999   # 'clobbered',
2000   # 'missing-field-initializers',
2001   # 'sign-compare',
2002   # 'unused-parameter',
2005 foreach w : negative_warning_flags
2006   if cc.has_argument('-W' + w)
2007     cflags_warn += '-Wno-' + w
2008   endif
2009   if llvm.found() and cpp.has_argument('-W' + w)
2010     cxxflags_warn += '-Wno-' + w
2011   endif
2012 endforeach
2015 if cc.get_id() == 'msvc'
2016   cflags_warn += [
2017     '/wd4018', # signed/unsigned mismatch
2018     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
2019     '/wd4273', # inconsistent DLL linkage
2020     '/wd4101', # unreferenced local variable
2021     '/wd4102', # unreferenced label
2022     '/wd4090', # different 'modifier' qualifiers
2023     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
2024   ]
2026   cppflags += [
2027     '/DWIN32',
2028     '/DWINDOWS',
2029     '/D__WINDOWS__',
2030     '/D__WIN32__',
2031     '/D_CRT_SECURE_NO_DEPRECATE',
2032     '/D_CRT_NONSTDC_NO_DEPRECATE',
2033   ]
2035   # We never need export libraries. As link.exe reports their creation, they
2036   # are unnecessarily noisy. Similarly, we don't need import library for
2037   # modules, we only import them dynamically, and they're also noisy.
2038   ldflags += '/NOEXP'
2039   ldflags_mod += '/NOIMPLIB'
2040 endif
2043 # Compute flags that are built into Meson.  We need these to
2044 # substitute into Makefile.global and for pg_config.  We only compute
2045 # the flags for Unix-style compilers, since that's the only style that
2046 # would use Makefile.global or pg_config.
2048 # We don't use get_option('warning_level') here, because the other
2049 # warning levels are not useful with PostgreSQL source code.
2050 common_builtin_flags = ['-Wall']
2052 if get_option('debug')
2053   common_builtin_flags += ['-g']
2054 endif
2056 optimization = get_option('optimization')
2057 if optimization == '0'
2058   common_builtin_flags += ['-O0']
2059 elif optimization == '1'
2060   common_builtin_flags += ['-O1']
2061 elif optimization == '2'
2062   common_builtin_flags += ['-O2']
2063 elif optimization == '3'
2064   common_builtin_flags += ['-O3']
2065 elif optimization == 's'
2066   common_builtin_flags += ['-Os']
2067 endif
2069 cflags_builtin = cc.get_supported_arguments(common_builtin_flags)
2070 if llvm.found()
2071   cxxflags_builtin = cpp.get_supported_arguments(common_builtin_flags)
2072 endif
2076 ###############################################################
2077 # Atomics
2078 ###############################################################
2080 atomic_checks = [
2081   {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2082    'desc': '__sync_lock_test_and_set(char)',
2083    'test': '''
2084 char lock = 0;
2085 __sync_lock_test_and_set(&lock, 1);
2086 __sync_lock_release(&lock);'''},
2088   {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2089    'desc': '__sync_lock_test_and_set(int32)',
2090    'test': '''
2091 int lock = 0;
2092 __sync_lock_test_and_set(&lock, 1);
2093 __sync_lock_release(&lock);'''},
2095   {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2096    'desc': '__sync_val_compare_and_swap(int32)',
2097    'test': '''
2098 int val = 0;
2099 __sync_val_compare_and_swap(&val, 0, 37);'''},
2101   {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2102    'desc': '__sync_val_compare_and_swap(int64)',
2103    'test': '''
2104 int64_t val = 0;
2105 __sync_val_compare_and_swap(&val, 0, 37);'''},
2107   {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2108    'desc': ' __atomic_compare_exchange_n(int32)',
2109    'test': '''
2110 int val = 0;
2111 int expect = 0;
2112 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2114   {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2115    'desc': ' __atomic_compare_exchange_n(int64)',
2116    'test': '''
2117 int64_t val = 0;
2118 int64_t expect = 0;
2119 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2122 foreach check : atomic_checks
2123   test = '''
2124 #include <stdint.h>
2125 int main(void)
2128 }'''.format(check['test'])
2130   cdata.set(check['name'],
2131     cc.links(test,
2132       name: check['desc'],
2133       args: test_c_args) ? 1 : false
2134   )
2135 endforeach
2138 ###############################################################
2139 # Check for the availability of XSAVE intrinsics.
2140 ###############################################################
2142 if host_cpu == 'x86' or host_cpu == 'x86_64'
2144   prog = '''
2145 #include <immintrin.h>
2147 #if defined(__has_attribute) && __has_attribute (target)
2148 __attribute__((target("xsave")))
2149 #endif
2150 int main(void)
2152     return _xgetbv(0) & 0xe0;
2156   if cc.links(prog, name: 'XSAVE intrinsics', args: test_c_args)
2157     cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2158   endif
2160 endif
2163 ###############################################################
2164 # Check for the availability of AVX-512 popcount intrinsics.
2165 ###############################################################
2167 if host_cpu == 'x86_64'
2169   prog = '''
2170 #include <immintrin.h>
2171 #include <stdint.h>
2173 #if defined(__has_attribute) && __has_attribute (target)
2174 __attribute__((target("avx512vpopcntdq,avx512bw")))
2175 #endif
2176 int main(void)
2178     const char buf[sizeof(__m512i)];
2179     int64_t popcnt = 0;
2180     __m512i accum = _mm512_setzero_si512();
2181     const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2182     const __m512i cnt = _mm512_popcnt_epi64(val);
2183     accum = _mm512_add_epi64(accum, cnt);
2184     popcnt = _mm512_reduce_add_epi64(accum);
2185     /* return computed value, to prevent the above being optimized away */
2186     return popcnt == 0;
2190   if cc.links(prog, name: 'AVX-512 popcount', args: test_c_args)
2191     cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2192   endif
2194 endif
2197 ###############################################################
2198 # Select CRC-32C implementation.
2200 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2201 # use the special CRC instructions for calculating CRC-32C. If we're not
2202 # targeting such a processor, but we can nevertheless produce code that uses
2203 # the SSE intrinsics, compile both implementations and select which one to use
2204 # at runtime, depending on whether SSE 4.2 is supported by the processor we're
2205 # running on.
2207 # Similarly, if we are targeting an ARM processor that has the CRC
2208 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2209 # we're not targeting such a processor, but can nevertheless produce code that
2210 # uses the CRC instructions, compile both, and select at runtime.
2212 # Note that we do not use __attribute__((target("..."))) for the ARM CRC
2213 # instructions because until clang 16, using the ARM intrinsics still requires
2214 # special -march flags.  Perhaps we can re-evaluate this decision after some
2215 # time has passed.
2216 ###############################################################
2218 have_optimized_crc = false
2219 cflags_crc = []
2220 if host_cpu == 'x86' or host_cpu == 'x86_64'
2222   if cc.get_id() == 'msvc'
2223     cdata.set('USE_SSE42_CRC32C', false)
2224     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2225     have_optimized_crc = true
2226   else
2228     prog = '''
2229 #include <nmmintrin.h>
2231 #if defined(__has_attribute) && __has_attribute (target)
2232 __attribute__((target("sse4.2")))
2233 #endif
2234 int main(void)
2236     unsigned int crc = 0;
2237     crc = _mm_crc32_u8(crc, 0);
2238     crc = _mm_crc32_u32(crc, 0);
2239     /* return computed value, to prevent the above being optimized away */
2240     return crc == 0;
2244     if not cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32',
2245           args: test_c_args)
2246       # Do not use Intel SSE 4.2
2247     elif (cc.get_define('__SSE4_2__') != '')
2248       # Use Intel SSE 4.2 unconditionally.
2249       cdata.set('USE_SSE42_CRC32C', 1)
2250       have_optimized_crc = true
2251     else
2252       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2253       # the runtime check.
2254       cdata.set('USE_SSE42_CRC32C', false)
2255       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2256       have_optimized_crc = true
2257     endif
2259   endif
2261 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2263   prog = '''
2264 #include <arm_acle.h>
2266 int main(void)
2268     unsigned int crc = 0;
2269     crc = __crc32cb(crc, 0);
2270     crc = __crc32ch(crc, 0);
2271     crc = __crc32cw(crc, 0);
2272     crc = __crc32cd(crc, 0);
2274     /* return computed value, to prevent the above being optimized away */
2275     return crc == 0;
2279   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2280       args: test_c_args)
2281     # Use ARM CRC Extension unconditionally
2282     cdata.set('USE_ARMV8_CRC32C', 1)
2283     have_optimized_crc = true
2284   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
2285       args: test_c_args + ['-march=armv8-a+crc+simd'])
2286     # Use ARM CRC Extension, with runtime check
2287     cflags_crc += '-march=armv8-a+crc+simd'
2288     cdata.set('USE_ARMV8_CRC32C', false)
2289     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2290     have_optimized_crc = true
2291   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2292       args: test_c_args + ['-march=armv8-a+crc'])
2293     # Use ARM CRC Extension, with runtime check
2294     cflags_crc += '-march=armv8-a+crc'
2295     cdata.set('USE_ARMV8_CRC32C', false)
2296     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2297     have_optimized_crc = true
2298   endif
2300 elif host_cpu == 'loongarch64'
2302   prog = '''
2303 int main(void)
2305     unsigned int crc = 0;
2306     crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2307     crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2308     crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2309     crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2311     /* return computed value, to prevent the above being optimized away */
2312     return crc == 0;
2316   if cc.links(prog, name: '__builtin_loongarch_crcc_w_b_w, __builtin_loongarch_crcc_w_h_w, __builtin_loongarch_crcc_w_w_w, and __builtin_loongarch_crcc_w_d_w',
2317       args: test_c_args)
2318     # Use LoongArch CRC instruction unconditionally
2319     cdata.set('USE_LOONGARCH_CRC32C', 1)
2320     have_optimized_crc = true
2321   endif
2323 endif
2325 if not have_optimized_crc
2326   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2327   # support.
2328   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2329 endif
2333 ###############################################################
2334 # Other CPU specific stuff
2335 ###############################################################
2337 if host_cpu == 'x86_64'
2339   if cc.compiles('''
2340       void main(void)
2341       {
2342           long long x = 1; long long r;
2343           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2344       }''',
2345       name: '@0@: popcntq instruction'.format(host_cpu),
2346       args: test_c_args)
2347     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2348   endif
2350 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2351   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2352   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2353     if cc.compiles('''
2354       static inline int
2355       addi(int ra, int si)
2356       {
2357           int res = 0;
2358           if (__builtin_constant_p(si))
2359               __asm__ __volatile__(
2360                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2361           return res;
2362       }
2363       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2364       ''',
2365       name: '@0@: "i"(x) when __builtin_constant_p(x)'.format(host_cpu),
2366       args: test_c_args)
2367       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2368     endif
2369   endif
2370 endif
2374 ###############################################################
2375 # Library / OS tests
2376 ###############################################################
2378 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2379 # unnecessary checks over and over, particularly on windows.
2380 header_checks = [
2381   'atomic.h',
2382   'copyfile.h',
2383   'crtdefs.h',
2384   'execinfo.h',
2385   'getopt.h',
2386   'ifaddrs.h',
2387   'mbarrier.h',
2388   'strings.h',
2389   'sys/epoll.h',
2390   'sys/event.h',
2391   'sys/personality.h',
2392   'sys/prctl.h',
2393   'sys/procctl.h',
2394   'sys/signalfd.h',
2395   'sys/ucred.h',
2396   'termios.h',
2397   'ucred.h',
2398   'xlocale.h',
2401 foreach header : header_checks
2402   varname = 'HAVE_' + header.underscorify().to_upper()
2404   # Emulate autoconf behaviour of not-found->undef, found->1
2405   found = cc.has_header(header,
2406     include_directories: postgres_inc, args: test_c_args)
2407   cdata.set(varname, found ? 1 : false,
2408             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2409 endforeach
2412 decl_checks = [
2413   ['F_FULLFSYNC', 'fcntl.h'],
2414   ['fdatasync', 'unistd.h'],
2415   ['posix_fadvise', 'fcntl.h'],
2416   ['strlcat', 'string.h'],
2417   ['strlcpy', 'string.h'],
2418   ['strnlen', 'string.h'],
2419   ['strsep',  'string.h'],
2422 # Need to check for function declarations for these functions, because
2423 # checking for library symbols wouldn't handle deployment target
2424 # restrictions on macOS
2425 decl_checks += [
2426   ['preadv', 'sys/uio.h'],
2427   ['pwritev', 'sys/uio.h'],
2430 # Check presence of some optional LLVM functions.
2431 if llvm.found()
2432   decl_checks += [
2433     ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2434     ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2435   ]
2436 endif
2438 foreach c : decl_checks
2439   func = c.get(0)
2440   header = c.get(1)
2441   args = c.get(2, {})
2442   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2444   found = cc.has_header_symbol(header, func,
2445     args: test_c_args, include_directories: postgres_inc,
2446     kwargs: args)
2447   cdata.set10(varname, found, description:
2448 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2449    don't.'''.format(func))
2450 endforeach
2453 if cc.has_type('struct option',
2454     args: test_c_args, include_directories: postgres_inc,
2455     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2456   cdata.set('HAVE_STRUCT_OPTION', 1)
2457 endif
2460 foreach c : ['opterr', 'optreset']
2461   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2463   if cc.links('''
2464 #include <unistd.h>
2465 int main(void)
2467     extern int @0@;
2468     @0@ = 1;
2470 '''.format(c), name: c, args: test_c_args)
2471     cdata.set(varname, 1)
2472   else
2473     cdata.set(varname, false)
2474   endif
2475 endforeach
2477 if cc.has_type('socklen_t',
2478     args: test_c_args, include_directories: postgres_inc,
2479     prefix: '''
2480 #include <sys/socket.h>''')
2481   cdata.set('HAVE_SOCKLEN_T', 1)
2482 endif
2484 if cc.has_member('struct sockaddr', 'sa_len',
2485     args: test_c_args, include_directories: postgres_inc,
2486     prefix: '''
2487 #include <sys/types.h>
2488 #include <sys/socket.h>''')
2489   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2490 endif
2492 if cc.has_member('struct tm', 'tm_zone',
2493     args: test_c_args, include_directories: postgres_inc,
2494     prefix: '''
2495 #include <sys/types.h>
2496 #include <time.h>
2497 ''')
2498   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2499 endif
2501 if cc.compiles('''
2502 #include <time.h>
2503 extern int foo(void);
2504 int foo(void)
2506     return timezone / 60;
2508 ''',
2509     name: 'global variable `timezone\' exists',
2510     args: test_c_args, include_directories: postgres_inc)
2511   cdata.set('HAVE_INT_TIMEZONE', 1)
2512 else
2513   cdata.set('HAVE_INT_TIMEZONE', false)
2514 endif
2516 if cc.has_type('union semun',
2517     args: test_c_args,
2518     include_directories: postgres_inc,
2519     prefix: '''
2520 #include <sys/types.h>
2521 #include <sys/ipc.h>
2522 #include <sys/sem.h>
2523 ''')
2524   cdata.set('HAVE_UNION_SEMUN', 1)
2525 endif
2527 if cc.compiles('''
2528 #include <string.h>
2529 int main(void)
2531   char buf[100];
2532   switch (strerror_r(1, buf, sizeof(buf)))
2533   { case 0: break; default: break; }
2534 }''',
2535     name: 'strerror_r',
2536     args: test_c_args, include_directories: postgres_inc)
2537   cdata.set('STRERROR_R_INT', 1)
2538 else
2539   cdata.set('STRERROR_R_INT', false)
2540 endif
2542 # Check if the C compiler understands typeof or a variant.  Define
2543 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2544 foreach kw : ['typeof', '__typeof__']
2545   if cc.compiles('''
2546 int main(void)
2548     int x = 0;
2549     @0@(x) y;
2550     y = x;
2551     return y;
2553 '''.format(kw),
2554     name: kw,
2555     args: test_c_args, include_directories: postgres_inc)
2557     cdata.set('HAVE_TYPEOF', 1)
2558     if kw != 'typeof'
2559       cdata.set('typeof', kw)
2560     endif
2562     break
2563   endif
2564 endforeach
2567 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2568 # understands, because it conflicts with __declspec(restrict). Therefore we
2569 # define pg_restrict to the appropriate definition, which presumably won't
2570 # conflict.
2572 # We assume C99 support, so we don't need to make this conditional.
2573 cdata.set('pg_restrict', '__restrict')
2576 # Most libraries are included only if they demonstrably provide a function we
2577 # need, but libm is an exception: always include it, because there are too
2578 # many compilers that play cute optimization games that will break probes for
2579 # standard functions such as pow().
2580 os_deps += cc.find_library('m', required: false)
2582 rt_dep = cc.find_library('rt', required: false)
2584 dl_dep = cc.find_library('dl', required: false)
2586 util_dep = cc.find_library('util', required: false)
2588 getopt_dep = cc.find_library('getopt', required: false)
2589 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2590 # Check if we want to replace getopt/getopt_long even if provided by the system
2591 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2592 #   so always use our version on Windows
2593 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2594 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2595 # - We want to use system's getopt_long() only if the system provides struct
2596 #   option
2597 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2598 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2600 # Required on BSDs
2601 execinfo_dep = cc.find_library('execinfo', required: false)
2603 if host_system == 'cygwin'
2604   cygipc_dep = cc.find_library('cygipc', required: false)
2605 else
2606   cygipc_dep = not_found_dep
2607 endif
2609 if host_system == 'sunos'
2610   socket_dep = cc.find_library('socket', required: false)
2611 else
2612   socket_dep = not_found_dep
2613 endif
2615 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2616 # unnecessary checks over and over, particularly on windows.
2617 func_checks = [
2618   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2619   ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2620   ['copyfile'],
2621   ['copy_file_range'],
2622   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2623   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2624   # required. Just checking for dlsym() ought to suffice.
2625   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2626   ['elf_aux_info'],
2627   ['explicit_bzero'],
2628   ['getauxval'],
2629   ['getifaddrs'],
2630   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2631   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2632   ['getpeereid'],
2633   ['getpeerucred'],
2634   ['inet_aton'],
2635   ['inet_pton'],
2636   ['kqueue'],
2637   ['mbstowcs_l'],
2638   ['memset_s'],
2639   ['mkdtemp'],
2640   ['posix_fadvise'],
2641   ['posix_fallocate'],
2642   ['ppoll'],
2643   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2644   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2645   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2646   ['setproctitle', {'dependencies': [util_dep]}],
2647   ['setproctitle_fast'],
2648   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2649   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2650   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2651   ['socket', {'dependencies': [socket_dep], 'define': false}],
2652   ['strchrnul'],
2653   ['strerror_r', {'dependencies': [thread_dep]}],
2654   ['strlcat'],
2655   ['strlcpy'],
2656   ['strnlen'],
2657   ['strsep'],
2658   ['strsignal'],
2659   ['sync_file_range'],
2660   ['syncfs'],
2661   ['uselocale'],
2662   ['wcstombs_l'],
2665 func_check_results = {}
2666 foreach c : func_checks
2667   func = c.get(0)
2668   kwargs = c.get(1, {})
2669   deps = kwargs.get('dependencies', [])
2671   if kwargs.get('skip', false)
2672     continue
2673   endif
2675   found = cc.has_function(func, args: test_c_args)
2677   if not found
2678     foreach dep : deps
2679       if not dep.found()
2680         continue
2681       endif
2682       found = cc.has_function(func, args: test_c_args,
2683                               dependencies: [dep])
2684       if found
2685         os_deps += dep
2686         break
2687       endif
2688     endforeach
2689   endif
2691   func_check_results += {func: found}
2693   if kwargs.get('define', true)
2694     # Emulate autoconf behaviour of not-found->undef, found->1
2695     cdata.set('HAVE_' + func.underscorify().to_upper(),
2696               found  ? 1 : false,
2697               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2698   endif
2699 endforeach
2702 if cc.has_function('syslog', args: test_c_args) and \
2703     cc.check_header('syslog.h', args: test_c_args)
2704   cdata.set('HAVE_SYSLOG', 1)
2705 endif
2708 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2709 # semaphores
2710 if sema_kind == 'unnamed_posix' and \
2711    not func_check_results.get('sem_init', false)
2712   sema_kind = 'sysv'
2713 endif
2715 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2716 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2718 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2719 cdata.set_quoted('DLSUFFIX', dlsuffix)
2722 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2723 cdata.set_quoted('PG_VERSION_STR',
2724   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2725     pg_version, host_machine.cpu_family(), host_system,
2726     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2727   )
2731 ###############################################################
2732 # NLS / Gettext
2733 ###############################################################
2735 nlsopt = get_option('nls')
2736 libintl = not_found_dep
2738 if not nlsopt.disabled()
2739   # otherwise there'd be lots of
2740   # "Gettext not found, all translation (po) targets will be ignored."
2741   # warnings if not found.
2742   msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2744   # meson 0.59 has this wrapped in dependency('intl')
2745   if (msgfmt.found() and
2746       cc.check_header('libintl.h', required: nlsopt,
2747         args: test_c_args, include_directories: postgres_inc))
2749     # in libc
2750     if cc.has_function('ngettext')
2751       libintl = declare_dependency()
2752     else
2753       libintl = cc.find_library('intl',
2754         has_headers: ['libintl.h'], required: nlsopt,
2755         header_include_directories: postgres_inc,
2756         dirs: test_lib_d)
2757     endif
2758   endif
2760   if libintl.found()
2761     i18n = import('i18n')
2762     cdata.set('ENABLE_NLS', 1)
2763   endif
2764 endif
2768 ###############################################################
2769 # Build
2770 ###############################################################
2772 # Set up compiler / linker arguments to be used everywhere, individual targets
2773 # can add further args directly, or indirectly via dependencies
2774 add_project_arguments(cflags, language: ['c'])
2775 add_project_arguments(cppflags, language: ['c'])
2776 add_project_arguments(cflags_warn, language: ['c'])
2777 add_project_arguments(cxxflags, language: ['cpp'])
2778 add_project_arguments(cppflags, language: ['cpp'])
2779 add_project_arguments(cxxflags_warn, language: ['cpp'])
2780 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2783 # Collect a number of lists of things while recursing through the source
2784 # tree. Later steps then can use those.
2786 # list of targets for various alias targets
2787 backend_targets = []
2788 bin_targets = []
2789 pl_targets = []
2790 contrib_targets = []
2791 testprep_targets = []
2792 nls_targets = []
2795 # Define the tests to distribute them to the correct test styles later
2796 test_deps = []
2797 tests = []
2800 # Default options for targets
2802 # First identify rpaths
2803 bin_install_rpaths = []
2804 lib_install_rpaths = []
2805 mod_install_rpaths = []
2808 # Don't add rpaths on darwin for now - as long as only absolute references to
2809 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2810 # their final destination.
2811 if host_system != 'darwin'
2812   # Add absolute path to libdir to rpath. This ensures installed binaries /
2813   # libraries find our libraries (mainly libpq).
2814   bin_install_rpaths += dir_prefix / dir_lib
2815   lib_install_rpaths += dir_prefix / dir_lib
2816   mod_install_rpaths += dir_prefix / dir_lib
2818   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2819   #
2820   # Not needed on darwin even if we use relative rpaths for our own libraries,
2821   # as the install_name of libraries in extra_lib_dirs will point to their
2822   # location anyway.
2823   bin_install_rpaths += postgres_lib_d
2824   lib_install_rpaths += postgres_lib_d
2825   mod_install_rpaths += postgres_lib_d
2826 endif
2829 # Define arguments for default targets
2831 default_target_args = {
2832   'implicit_include_directories': false,
2833   'install': true,
2836 default_lib_args = default_target_args + {
2837   'name_prefix': '',
2840 internal_lib_args = default_lib_args + {
2841   'build_by_default': false,
2842   'install': false,
2845 default_mod_args = default_lib_args + {
2846   'name_prefix': '',
2847   'install_dir': dir_lib_pkg,
2850 default_bin_args = default_target_args + {
2851   'install_dir': dir_bin,
2854 if get_option('rpath')
2855   default_lib_args += {
2856     'install_rpath': ':'.join(lib_install_rpaths),
2857   }
2859   default_mod_args += {
2860     'install_rpath': ':'.join(mod_install_rpaths),
2861   }
2863   default_bin_args += {
2864     'install_rpath': ':'.join(bin_install_rpaths),
2865   }
2866 endif
2869 # Helper for exporting a limited number of symbols
2870 gen_export_kwargs = {
2871   'input': 'exports.txt',
2872   'output': '@BASENAME@.'+export_file_suffix,
2873   'command': [perl, files('src/tools/gen_export.pl'),
2874    '--format', export_file_format,
2875    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2876   'build_by_default': false,
2877   'install': false,
2883 ### Helpers for custom targets used across the tree
2886 catalog_pm = files('src/backend/catalog/Catalog.pm')
2887 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2888 gen_kwlist_deps = [perfect_hash_pm]
2889 gen_kwlist_cmd = [
2890   perl, '-I', '@SOURCE_ROOT@/src/tools',
2891   files('src/tools/gen_keywordlist.pl'),
2892   '--output', '@OUTDIR@', '@INPUT@']
2897 ### windows resources related stuff
2900 if host_system == 'windows'
2901   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2902   win32ver_rc = files('src/port/win32ver.rc')
2903   rcgen = find_program('src/tools/rcgen', native: true)
2905   rcgen_base_args = [
2906     '--srcdir', '@SOURCE_DIR@',
2907     '--builddir', meson.build_root(),
2908     '--rcout', '@OUTPUT0@',
2909     '--out', '@OUTPUT1@',
2910     '--input', '@INPUT@',
2911     '@EXTRA_ARGS@',
2912   ]
2914   if cc.get_argument_syntax() == 'msvc'
2915     rc = find_program('rc', required: true)
2916     rcgen_base_args += ['--rc', rc.path()]
2917     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2918   else
2919     windres = find_program('windres', required: true)
2920     rcgen_base_args += ['--windres', windres.path()]
2921     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2922   endif
2924   # msbuild backend doesn't support this atm
2925   if meson.backend() == 'ninja'
2926     rcgen_base_args += ['--depfile', '@DEPFILE@']
2927   endif
2929   rcgen_bin_args = rcgen_base_args + [
2930     '--VFT_TYPE', 'VFT_APP',
2931     '--FILEENDING', 'exe',
2932     '--ICO', pg_ico
2933   ]
2935   rcgen_lib_args = rcgen_base_args + [
2936     '--VFT_TYPE', 'VFT_DLL',
2937     '--FILEENDING', 'dll',
2938   ]
2940   rc_bin_gen = generator(rcgen,
2941     depfile: '@BASENAME@.d',
2942     arguments: rcgen_bin_args,
2943     output: rcgen_outputs,
2944   )
2946   rc_lib_gen = generator(rcgen,
2947     depfile: '@BASENAME@.d',
2948     arguments: rcgen_lib_args,
2949     output: rcgen_outputs,
2950   )
2951 endif
2955 # headers that the whole build tree depends on
2956 generated_headers = []
2957 # headers that the backend build depends on
2958 generated_backend_headers = []
2959 # configure_files() output, needs a way of converting to file names
2960 configure_files = []
2962 # generated files that might conflict with a partial in-tree autoconf build
2963 generated_sources = []
2964 # same, for paths that differ between autoconf / meson builds
2965 # elements are [dir, [files]]
2966 generated_sources_ac = {}
2969 # First visit src/include - all targets creating headers are defined
2970 # within. That makes it easy to add the necessary dependencies for the
2971 # subsequent build steps.
2973 subdir('src/include')
2975 subdir('config')
2977 # Then through src/port and src/common, as most other things depend on them
2979 frontend_port_code = declare_dependency(
2980   compile_args: ['-DFRONTEND'],
2981   include_directories: [postgres_inc],
2982   dependencies: os_deps,
2985 backend_port_code = declare_dependency(
2986   compile_args: ['-DBUILDING_DLL'],
2987   include_directories: [postgres_inc],
2988   sources: [errcodes], # errcodes.h is needed due to use of ereport
2989   dependencies: os_deps,
2992 subdir('src/port')
2994 frontend_common_code = declare_dependency(
2995   compile_args: ['-DFRONTEND'],
2996   include_directories: [postgres_inc],
2997   sources: generated_headers,
2998   dependencies: [os_deps, zlib, zstd, lz4],
3001 backend_common_code = declare_dependency(
3002   compile_args: ['-DBUILDING_DLL'],
3003   include_directories: [postgres_inc],
3004   sources: generated_headers,
3005   dependencies: [os_deps, zlib, zstd],
3008 subdir('src/common')
3010 # all shared libraries should depend on shlib_code
3011 shlib_code = declare_dependency(
3012   link_args: ldflags_sl,
3015 # all static libraries not part of the backend should depend on this
3016 frontend_stlib_code = declare_dependency(
3017   include_directories: [postgres_inc],
3018   link_with: [common_static, pgport_static],
3019   sources: generated_headers,
3020   dependencies: [os_deps, libintl],
3023 # all shared libraries not part of the backend should depend on this
3024 frontend_shlib_code = declare_dependency(
3025   include_directories: [postgres_inc],
3026   link_with: [common_shlib, pgport_shlib],
3027   sources: generated_headers,
3028   dependencies: [shlib_code, os_deps, libintl],
3031 # Dependencies both for static and shared libpq
3032 libpq_deps += [
3033   thread_dep,
3035   gssapi,
3036   ldap_r,
3037   libintl,
3038   ssl,
3041 subdir('src/interfaces/libpq')
3042 # fe_utils depends on libpq
3043 subdir('src/fe_utils')
3045 # for frontend binaries
3046 frontend_code = declare_dependency(
3047   include_directories: [postgres_inc],
3048   link_with: [fe_utils, common_static, pgport_static],
3049   sources: generated_headers,
3050   dependencies: [os_deps, libintl],
3053 backend_both_deps += [
3054   thread_dep,
3055   bsd_auth,
3056   gssapi,
3057   icu,
3058   icu_i18n,
3059   ldap,
3060   libintl,
3061   libxml,
3062   lz4,
3063   pam,
3064   ssl,
3065   systemd,
3066   zlib,
3067   zstd,
3070 backend_mod_deps = backend_both_deps + os_deps
3072 backend_code = declare_dependency(
3073   compile_args: ['-DBUILDING_DLL'],
3074   include_directories: [postgres_inc],
3075   link_args: ldflags_be,
3076   link_with: [],
3077   sources: generated_headers + generated_backend_headers,
3078   dependencies: os_deps + backend_both_deps + backend_deps,
3081 # install these files only during test, not main install
3082 test_install_data = []
3083 test_install_libs = []
3085 # src/backend/meson.build defines backend_mod_code used for extension
3086 # libraries.
3089 # Then through the main sources. That way contrib can have dependencies on
3090 # main sources. Note that this explicitly doesn't enter src/test, right now a
3091 # few regression tests depend on contrib files.
3093 subdir('src')
3095 subdir('contrib')
3097 subdir('src/test')
3098 subdir('src/interfaces/libpq/test')
3099 subdir('src/interfaces/ecpg/test')
3101 subdir('doc/src/sgml')
3103 generated_sources_ac += {'': ['GNUmakefile']}
3105 # After processing src/test, add test_install_libs to the testprep_targets
3106 # to build them
3107 testprep_targets += test_install_libs
3110 # If there are any files in the source directory that we also generate in the
3111 # build directory, they might get preferred over the newly generated files,
3112 # e.g. because of a #include "file", which always will search in the current
3113 # directory first.
3114 message('checking for file conflicts between source and build directory')
3115 conflicting_files = []
3116 potentially_conflicting_files_t = []
3117 potentially_conflicting_files_t += generated_headers
3118 potentially_conflicting_files_t += generated_backend_headers
3119 potentially_conflicting_files_t += generated_backend_sources
3120 potentially_conflicting_files_t += generated_sources
3122 potentially_conflicting_files = []
3124 # convert all sources of potentially conflicting files into uniform shape
3125 foreach t : potentially_conflicting_files_t
3126   potentially_conflicting_files += t.full_path()
3127 endforeach
3128 foreach t1 : configure_files
3129   if meson.version().version_compare('>=0.59')
3130     t = fs.parent(t1) / fs.name(t1)
3131   else
3132     t = '@0@'.format(t1)
3133   endif
3134   potentially_conflicting_files += meson.current_build_dir() / t
3135 endforeach
3136 foreach sub, fnames : generated_sources_ac
3137   sub = meson.build_root() / sub
3138   foreach fname : fnames
3139     potentially_conflicting_files += sub / fname
3140   endforeach
3141 endforeach
3143 # find and report conflicting files
3144 foreach build_path : potentially_conflicting_files
3145   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3146   # str.replace is in 0.56
3147   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3148   if fs.exists(src_path) or fs.is_symlink(src_path)
3149     conflicting_files += src_path
3150   endif
3151 endforeach
3152 # XXX: Perhaps we should generate a file that would clean these up? The list
3153 # can be long.
3154 if conflicting_files.length() > 0
3155   errmsg_cleanup = '''
3156 Conflicting files in source directory:
3157   @0@
3159 The conflicting files need to be removed, either by removing the files listed
3160 above, or by running configure and then make maintainer-clean.
3162   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3163   error(errmsg_nonclean_base.format(errmsg_cleanup))
3164 endif
3168 ###############################################################
3169 # Install targets
3170 ###############################################################
3173 # We want to define additional install targets beyond what meson provides. For
3174 # that we need to define targets depending on nearly everything. We collected
3175 # the results of i18n.gettext() invocations into nls_targets, that also
3176 # includes maintainer targets though. Collect the ones we want as a dependency.
3178 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3179 # generation happens during install, so that's not a real issue.
3180 nls_mo_targets = []
3181 if libintl.found() and meson.version().version_compare('>=0.60')
3182   # use range() to avoid the flattening of the list that foreach() would do
3183   foreach off : range(0, nls_targets.length())
3184     # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3185     # -pot target 3) maintainer -pot target
3186     nls_mo_targets += nls_targets[off][0]
3187   endforeach
3188   alias_target('nls', nls_mo_targets)
3189 endif
3192 all_built = [
3193   backend_targets,
3194   bin_targets,
3195   libpq_st,
3196   pl_targets,
3197   contrib_targets,
3198   nls_mo_targets,
3199   testprep_targets,
3200   ecpg_targets,
3203 # Meson's default install target is quite verbose. Provide one that is quiet.
3204 install_quiet = custom_target('install-quiet',
3205   output: 'install-quiet',
3206   build_always_stale: true,
3207   build_by_default: false,
3208   command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3209   depends: all_built,
3212 # Target to install files used for tests, which aren't installed by default
3213 install_test_files_args = [
3214   install_files,
3215   '--prefix', dir_prefix,
3216   '--install', contrib_data_dir, test_install_data,
3217   '--install', dir_lib_pkg, test_install_libs,
3219 run_target('install-test-files',
3220   command: [python] + install_test_files_args,
3221   depends: testprep_targets,
3226 ###############################################################
3227 # Test prep
3228 ###############################################################
3230 # DESTDIR for the installation we'll run tests in
3231 test_install_destdir = meson.build_root() / 'tmp_install/'
3233 # DESTDIR + prefix appropriately munged
3234 if build_system != 'windows'
3235   # On unixoid systems this is trivial, we just prepend the destdir
3236   assert(dir_prefix.startswith('/')) # enforced by meson
3237   temp_install_bindir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_bin)
3238   temp_install_libdir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_lib)
3239 else
3240   # drives, drive-relative paths, etc make this complicated on windows, call
3241   # into a copy of meson's logic for it
3242   command = [
3243     python, '-c',
3244     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3245     test_install_destdir]
3246   temp_install_bindir = run_command(command, dir_prefix / dir_bin, check: true).stdout().strip()
3247   temp_install_libdir = run_command(command, dir_prefix / dir_lib, check: true).stdout().strip()
3248 endif
3250 meson_install_args = meson_args + ['install'] + {
3251     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3252     'muon': []
3253 }[meson_impl]
3255 # setup tests should be run first,
3256 # so define priority for these
3257 setup_tests_priority = 100
3258 test('tmp_install',
3259     meson_bin, args: meson_install_args ,
3260     env: {'DESTDIR':test_install_destdir},
3261     priority: setup_tests_priority,
3262     timeout: 300,
3263     is_parallel: false,
3264     suite: ['setup'])
3266 test('install_test_files',
3267     python,
3268     args: install_test_files_args + ['--destdir', test_install_destdir],
3269     priority: setup_tests_priority,
3270     is_parallel: false,
3271     suite: ['setup'])
3273 test_result_dir = meson.build_root() / 'testrun'
3276 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3277 # inevitable conflicts from running tests in parallel, hackishly assign
3278 # different ports for different tests.
3280 testport = 40000
3282 test_env = environment()
3284 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3285 test_env.set('PG_REGRESS', pg_regress.full_path())
3286 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3287 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3289 # Add the temporary installation to the library search path on platforms where
3290 # that works (everything but windows, basically). On windows everything
3291 # library-like gets installed into bindir, solving that issue.
3292 if library_path_var != ''
3293   test_env.prepend(library_path_var, temp_install_libdir)
3294 endif
3297 # Create (and remove old) initdb template directory. Tests use that, where
3298 # possible, to make it cheaper to run tests.
3300 # Use python to remove the old cached initdb, as we cannot rely on a working
3301 # 'rm' binary on windows.
3302 test('initdb_cache',
3303      python,
3304      args: [
3305        '-c', '''
3306 import shutil
3307 import sys
3308 import subprocess
3310 shutil.rmtree(sys.argv[1], ignore_errors=True)
3311 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3312 sys.exit(sp.returncode)
3313 ''',
3314        test_initdb_template,
3315        temp_install_bindir / 'initdb',
3316        '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3317        '--no-clean'
3318      ],
3319      priority: setup_tests_priority - 1,
3320      timeout: 300,
3321      is_parallel: false,
3322      env: test_env,
3323      suite: ['setup'])
3327 ###############################################################
3328 # Test Generation
3329 ###############################################################
3331 # When using a meson version understanding exclude_suites, define a
3332 # 'tmp_install' test setup (the default) that excludes tests running against a
3333 # pre-existing install and a 'running' setup that conflicts with creation of
3334 # the temporary installation and tap tests (which don't support running
3335 # against a running server).
3337 running_suites = []
3338 install_suites = []
3339 if meson.version().version_compare('>=0.57')
3340   runningcheck = true
3341 else
3342   runningcheck = false
3343 endif
3345 testwrap = files('src/tools/testwrap')
3347 foreach test_dir : tests
3348   testwrap_base = [
3349     testwrap,
3350     '--basedir', meson.build_root(),
3351     '--srcdir', test_dir['sd'],
3352     # Some test suites are not run by default but can be run if selected by the
3353     # user via variable PG_TEST_EXTRA. Pass configuration time value of
3354     # PG_TEST_EXTRA as an argument to testwrap so that it can be overridden by
3355     # run time value, if any.
3356     '--pg-test-extra', get_option('PG_TEST_EXTRA'),
3357   ]
3359   foreach kind, v : test_dir
3360     if kind in ['sd', 'bd', 'name']
3361       continue
3362     endif
3364     t = test_dir[kind]
3366     if kind in ['regress', 'isolation', 'ecpg']
3367       if kind == 'regress'
3368         runner = pg_regress
3369         fallback_dbname = 'regression_@0@'
3370       elif kind == 'isolation'
3371         runner = pg_isolation_regress
3372         fallback_dbname = 'isolation_regression_@0@'
3373       elif kind == 'ecpg'
3374         runner = pg_regress_ecpg
3375         fallback_dbname = 'ecpg_regression_@0@'
3376       endif
3378       test_group = test_dir['name']
3379       test_group_running = test_dir['name'] + '-running'
3381       test_output = test_result_dir / test_group / kind
3382       test_output_running = test_result_dir / test_group_running/ kind
3384       # Unless specified by the test, choose a non-conflicting database name,
3385       # to avoid conflicts when running against existing server.
3386       dbname = t.get('dbname',
3387         fallback_dbname.format(test_dir['name']))
3389       test_command_base = [
3390         runner.full_path(),
3391         '--inputdir', t.get('inputdir', test_dir['sd']),
3392         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3393         '--bindir', '',
3394         '--dlpath', test_dir['bd'],
3395         '--max-concurrent-tests=20',
3396         '--dbname', dbname,
3397       ] + t.get('regress_args', [])
3399       test_selection = []
3400       if t.has_key('schedule')
3401         test_selection += ['--schedule', t['schedule'],]
3402       endif
3404       if kind == 'isolation'
3405         test_selection += t.get('specs', [])
3406       else
3407         test_selection += t.get('sql', [])
3408       endif
3410       env = test_env
3411       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3413       test_kwargs = {
3414         'protocol': 'tap',
3415         'priority': 10,
3416         'timeout': 1000,
3417         'depends': test_deps + t.get('deps', []),
3418         'env': env,
3419       } + t.get('test_kwargs', {})
3421       test(test_group / kind,
3422         python,
3423         args: [
3424           testwrap_base,
3425           '--testgroup', test_group,
3426           '--testname', kind,
3427           '--',
3428           test_command_base,
3429           '--outputdir', test_output,
3430           '--temp-instance', test_output / 'tmp_check',
3431           '--port', testport.to_string(),
3432           test_selection,
3433         ],
3434         suite: test_group,
3435         kwargs: test_kwargs,
3436       )
3437       install_suites += test_group
3439       # some tests can't support running against running DB
3440       if runningcheck and t.get('runningcheck', true)
3441         test(test_group_running / kind,
3442           python,
3443           args: [
3444             testwrap_base,
3445             '--testgroup', test_group_running,
3446             '--testname', kind,
3447             '--',
3448             test_command_base,
3449             '--outputdir', test_output_running,
3450             test_selection,
3451           ],
3452           is_parallel: t.get('runningcheck-parallel', true),
3453           suite: test_group_running,
3454           kwargs: test_kwargs,
3455         )
3456         running_suites += test_group_running
3457       endif
3459       testport += 1
3460     elif kind == 'tap'
3461       testwrap_tap = testwrap_base
3462       if not tap_tests_enabled
3463         testwrap_tap += ['--skip', 'TAP tests not enabled']
3464       endif
3466       test_command = [
3467         perl.path(),
3468         '-I', meson.source_root() / 'src/test/perl',
3469         '-I', test_dir['sd'],
3470       ]
3472       # Add temporary install, the build directory for non-installed binaries and
3473       # also test/ for non-installed test binaries built separately.
3474       env = test_env
3475       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3477       foreach name, value : t.get('env', {})
3478         env.set(name, value)
3479       endforeach
3481       test_group = test_dir['name']
3482       test_kwargs = {
3483         'protocol': 'tap',
3484         'suite': test_group,
3485         'timeout': 1000,
3486         'depends': test_deps + t.get('deps', []),
3487         'env': env,
3488       } + t.get('test_kwargs', {})
3490       foreach onetap : t['tests']
3491         # Make tap test names prettier, remove t/ and .pl
3492         onetap_p = onetap
3493         if onetap_p.startswith('t/')
3494           onetap_p = onetap.split('t/')[1]
3495         endif
3496         if onetap_p.endswith('.pl')
3497           onetap_p = fs.stem(onetap_p)
3498         endif
3500         test(test_dir['name'] / onetap_p,
3501           python,
3502           kwargs: test_kwargs,
3503           args: testwrap_tap + [
3504             '--testgroup', test_dir['name'],
3505             '--testname', onetap_p,
3506             '--', test_command,
3507             test_dir['sd'] / onetap,
3508           ],
3509         )
3510       endforeach
3511       install_suites += test_group
3512     else
3513       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3514     endif
3516   endforeach # kinds of tests
3518 endforeach # directories with tests
3520 # repeat condition so meson realizes version dependency
3521 if meson.version().version_compare('>=0.57')
3522   add_test_setup('tmp_install',
3523     is_default: true,
3524     exclude_suites: running_suites)
3525   add_test_setup('running',
3526     exclude_suites: ['setup'] + install_suites)
3527 endif
3531 ###############################################################
3532 # Pseudo targets
3533 ###############################################################
3535 alias_target('backend', backend_targets)
3536 alias_target('bin', bin_targets + [libpq_st])
3537 alias_target('pl', pl_targets)
3538 alias_target('contrib', contrib_targets)
3539 alias_target('testprep', testprep_targets)
3541 alias_target('world', all_built, docs)
3542 alias_target('install-world', install_quiet, installdocs)
3544 run_target('help',
3545   command: [
3546     perl, '-ne', 'next if /^#/; print',
3547     files('doc/src/sgml/targets-meson.txt'),
3548   ]
3553 ###############################################################
3554 # Distribution archive
3555 ###############################################################
3557 # Meson has its own distribution building command (meson dist), but we
3558 # are not using that at this point.  The main problem is that, the way
3559 # they have implemented it, it is not deterministic.  Also, we want it
3560 # to be equivalent to the "make" version for the time being.  But the
3561 # target name "dist" in meson is reserved for that reason, so we call
3562 # the custom target "pgdist".
3564 git = find_program('git', required: false, native: true, disabler: true)
3565 bzip2 = find_program('bzip2', required: false, native: true)
3567 distdir = meson.project_name() + '-' + meson.project_version()
3569 pg_git_revision = get_option('PG_GIT_REVISION')
3571 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3572 # in case the environment has a different setting.  Without this, a
3573 # tarball created on Windows might be different than on, and unusable
3574 # on, Unix machines.
3576 tar_gz = custom_target('tar.gz',
3577   build_always_stale: true,
3578   command: [git, '-C', '@SOURCE_ROOT@',
3579             '-c', 'core.autocrlf=false',
3580             'archive',
3581             '--format', 'tar.gz',
3582             '-9',
3583             '--prefix', distdir + '/',
3584             '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3585             pg_git_revision],
3586   output: distdir + '.tar.gz',
3589 if bzip2.found()
3590   tar_bz2 = custom_target('tar.bz2',
3591     build_always_stale: true,
3592     command: [git, '-C', '@SOURCE_ROOT@',
3593               '-c', 'core.autocrlf=false',
3594               '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3595               'archive',
3596               '--format', 'tar.bz2',
3597               '--prefix', distdir + '/',
3598               '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3599               pg_git_revision],
3600     output: distdir + '.tar.bz2',
3601   )
3602 else
3603   tar_bz2 = custom_target('tar.bz2',
3604     command: [perl, '-e', 'exit 1'],
3605     output: distdir + '.tar.bz2',
3606   )
3607 endif
3609 alias_target('pgdist', [tar_gz, tar_bz2])
3611 # Make the standard "dist" command fail, to prevent accidental use.
3612 # But not if we are in a subproject, in case the parent project wants to
3613 # create a dist using the standard Meson command.
3614 if not meson.is_subproject()
3615   # We can only pass the identifier perl here when we depend on >= 0.55
3616   if meson.version().version_compare('>=0.55')
3617     meson.add_dist_script(perl, '-e', 'exit 1')
3618   endif
3619 endif
3623 ###############################################################
3624 # The End, The End, My Friend
3625 ###############################################################
3627 if meson.version().version_compare('>=0.57')
3629   summary(
3630     {
3631       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3632       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3633       'segment size': get_option('segsize_blocks') != 0 ?
3634         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3635         '@0@ GB'.format(get_option('segsize')),
3636     },
3637     section: 'Data layout',
3638   )
3640   summary(
3641     {
3642       'host system': '@0@ @1@'.format(host_system, host_cpu),
3643       'build system': '@0@ @1@'.format(build_machine.system(),
3644                                        build_machine.cpu_family()),
3645     },
3646     section: 'System',
3647   )
3649   summary(
3650     {
3651       'linker': '@0@'.format(cc.get_linker_id()),
3652       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3653     },
3654     section: 'Compiler',
3655   )
3657   summary(
3658     {
3659       'CPP FLAGS': ' '.join(cppflags),
3660       'C FLAGS, functional': ' '.join(cflags),
3661       'C FLAGS, warnings': ' '.join(cflags_warn),
3662       'C FLAGS, modules': ' '.join(cflags_mod),
3663       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3664       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3665     },
3666     section: 'Compiler Flags',
3667   )
3669   if llvm.found()
3670     summary(
3671       {
3672         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3673       },
3674       section: 'Compiler',
3675     )
3677     summary(
3678       {
3679         'C++ FLAGS, functional': ' '.join(cxxflags),
3680         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3681         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3682       },
3683       section: 'Compiler Flags',
3684     )
3685   endif
3687   summary(
3688     {
3689       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3690       'dtrace': dtrace,
3691       'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3692     },
3693     section: 'Programs',
3694   )
3696   summary(
3697     {
3698       'bonjour': bonjour,
3699       'bsd_auth': bsd_auth,
3700       'docs': docs_dep,
3701       'docs_pdf': docs_pdf_dep,
3702       'gss': gssapi,
3703       'icu': icu,
3704       'ldap': ldap,
3705       'libxml': libxml,
3706       'libxslt': libxslt,
3707       'llvm': llvm,
3708       'lz4': lz4,
3709       'nls': libintl,
3710       'openssl': ssl,
3711       'pam': pam,
3712       'plperl': perl_dep,
3713       'plpython': python3_dep,
3714       'pltcl': tcl_dep,
3715       'readline': readline,
3716       'selinux': selinux,
3717       'systemd': systemd,
3718       'uuid': uuid,
3719       'zlib': zlib,
3720       'zstd': zstd,
3721     },
3722     section: 'External libraries',
3723   )
3725 endif