1 # Copyright (c) 2022-2024, PostgreSQL Global Development Group
3 # Entry point for building PostgreSQL with meson
5 # Good starting points for writing meson.build files are:
6 # - https://mesonbuild.com/Syntax.html
7 # - https://mesonbuild.com/Reference-manual.html
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',
19 'warning_level=1', #-Wall equivalent
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',
31 ###############################################################
33 ###############################################################
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 ###############################################################
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 = '''
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.
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))
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')
107 backend_both_deps = []
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']
131 pg_version_arr = pg_version.split('.')
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
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'
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
197 portname = host_system
199 if host_system == 'cygwin'
200 sema_kind = 'unnamed_posix'
201 cppflags += '-D_GNU_SOURCE'
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'
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))
222 cflags += ['-isysroot', pg_sysroot]
223 ldflags += ['-isysroot', pg_sysroot]
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'
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
256 ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
258 elif host_system == 'openbsd'
261 elif host_system == 'sunos'
263 export_fmt = '-Wl,-M@0@'
264 cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
266 elif host_system == 'windows'
270 library_path_var = ''
272 export_file_format = 'win'
273 export_file_suffix = 'def'
274 if cc.get_id() == 'msvc'
275 export_fmt = '/DEF:@0@'
276 mod_link_with_name = '@0@.lib'
279 mod_link_with_name = 'lib@0@.a'
281 mod_link_args_fmt = ['@0@']
282 mod_link_with_dir = 'libdir'
287 cdata.set('WIN32_STACK_RLIMIT', 4194304)
288 if cc.get_id() == 'msvc'
289 ldflags += '/INCREMENTAL:NO'
290 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
291 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
293 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
294 # Need to allow multiple definitions, we e.g. want to override getopt.
295 ldflags += '-Wl,--allow-multiple-definition'
296 # Ensure we get MSVC-like linking behavior.
297 ldflags += '-Wl,--disable-auto-import'
300 os_deps += cc.find_library('ws2_32', required: true)
301 secur32_dep = cc.find_library('secur32', required: true)
302 backend_deps += secur32_dep
303 libpq_deps += secur32_dep
305 postgres_inc_d += 'src/include/port/win32'
306 if cc.get_id() == 'msvc'
307 postgres_inc_d += 'src/include/port/win32_msvc'
310 windows = import('windows')
313 # XXX: Should we add an option to override the host_system as an escape
315 error('unknown host system: @0@'.format(host_system))
320 ###############################################################
322 ###############################################################
325 perl = find_program(get_option('PERL'), required: true, native: true)
326 python = find_program(get_option('PYTHON'), required: true, native: true)
327 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
328 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
329 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
330 prove = find_program(get_option('PROVE'), native: true, required: false)
331 tar = find_program(get_option('TAR'), native: true, required: false)
332 gzip = find_program(get_option('GZIP'), native: true, required: false)
333 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
334 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
335 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
336 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
337 missing = find_program('config/missing', native: true)
338 cp = find_program('cp', required: false, native: true)
339 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
340 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
344 bison_version_c = run_command(bison, '--version', check: true)
345 # bison version string helpfully is something like
346 # >>bison (GNU bison) 3.8.1<<
347 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
348 if bison_version.version_compare('>=3.0')
349 bison_flags += ['-Wno-deprecated']
352 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
354 'output': ['@BASENAME@.c', '@BASENAME@.h'],
355 'command': bison_cmd,
360 flex_version_c = run_command(flex, '--version', check: true)
361 flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
363 flex_wrapper = files('src/tools/pgflex')
364 flex_cmd = [python, flex_wrapper,
365 '--builddir', '@BUILD_ROOT@',
366 '--srcdir', '@SOURCE_ROOT@',
367 '--privatedir', '@PRIVATE_DIR@',
368 '--flex', flex, '--perl', perl,
369 '-i', '@INPUT@', '-o', '@OUTPUT0@',
372 wget = find_program('wget', required: false, native: true)
373 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
375 install_files = files('src/tools/install_files')
379 ###############################################################
380 # Path to meson (for tests etc)
381 ###############################################################
383 # NB: this should really be part of meson, see
384 # https://github.com/mesonbuild/meson/issues/8511
385 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
387 if meson_binpath_r.stdout() == ''
388 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
389 meson_binpath_r.returncode(),
390 meson_binpath_r.stdout(),
391 meson_binpath_r.stderr()))
394 meson_binpath_s = meson_binpath_r.stdout().split('\n')
395 meson_binpath_len = meson_binpath_s.length()
397 if meson_binpath_len < 1
398 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
405 foreach e : meson_binpath_s
416 if meson_impl not in ['muon', 'meson']
417 error('unknown meson implementation "@0@"'.format(meson_impl))
420 meson_bin = find_program(meson_binpath, native: true)
424 ###############################################################
426 ###############################################################
428 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
429 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
431 blocksize = get_option('blocksize').to_int() * 1024
433 if get_option('segsize_blocks') != 0
434 if get_option('segsize') != 1
435 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
438 segsize = get_option('segsize_blocks')
440 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
443 cdata.set('BLCKSZ', blocksize, description:
444 '''Size of a disk block --- this also limits the size of a tuple. You can set
445 it bigger if you need bigger tuples (although TOAST should reduce the need
446 to have large tuples, since fields can be spread across multiple tuples).
447 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
448 currently 2^15 (32768). This is determined by the 15-bit widths of the
449 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
450 Changing BLCKSZ requires an initdb.''')
452 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
453 cdata.set('RELSEG_SIZE', segsize)
454 cdata.set('DEF_PGPORT', get_option('pgport'))
455 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
456 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
457 if get_option('system_tzdata') != ''
458 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
463 ###############################################################
465 ###############################################################
467 # These are set by the equivalent --xxxdir configure options. We
468 # append "postgresql" to some of them, if the string does not already
469 # contain "pgsql" or "postgres", in order to avoid directory clutter.
473 dir_prefix = get_option('prefix')
475 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
477 dir_bin = get_option('bindir')
479 dir_data = get_option('datadir')
480 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
481 dir_data = dir_data / pkg
484 dir_sysconf = get_option('sysconfdir')
485 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
486 dir_sysconf = dir_sysconf / pkg
489 dir_lib = get_option('libdir')
491 dir_lib_pkg = dir_lib
492 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
493 dir_lib_pkg = dir_lib_pkg / pkg
496 dir_pgxs = dir_lib_pkg / 'pgxs'
498 dir_include = get_option('includedir')
500 dir_include_pkg = dir_include
501 dir_include_pkg_rel = ''
502 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
503 dir_include_pkg = dir_include_pkg / pkg
504 dir_include_pkg_rel = pkg
507 dir_man = get_option('mandir')
509 # FIXME: These used to be separately configurable - worth adding?
510 dir_doc = get_option('datadir') / 'doc'
511 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
512 dir_doc = dir_doc / pkg
514 dir_doc_html = dir_doc / 'html'
516 dir_locale = get_option('localedir')
520 dir_bitcode = dir_lib_pkg / 'bitcode'
521 dir_include_internal = dir_include_pkg / 'internal'
522 dir_include_server = dir_include_pkg / 'server'
523 dir_include_extension = dir_include_server / 'extension'
524 dir_data_extension = dir_data / 'extension'
525 dir_doc_extension = dir_doc / 'extension'
529 ###############################################################
530 # Search paths, preparation for compiler tests
532 # NB: Arguments added later are not automatically used for subsequent
533 # configuration-time checks (so they are more isolated). If they should be
534 # used, they need to be added to test_c_args as well.
535 ###############################################################
537 postgres_inc = [include_directories(postgres_inc_d)]
538 test_lib_d = postgres_lib_d
539 test_c_args = cppflags + cflags
543 ###############################################################
545 ###############################################################
547 bsd_authopt = get_option('bsd_auth')
548 bsd_auth = not_found_dep
549 if cc.check_header('bsd_auth.h', required: bsd_authopt,
550 args: test_c_args, include_directories: postgres_inc)
551 cdata.set('USE_BSD_AUTH', 1)
552 bsd_auth = declare_dependency()
557 ###############################################################
560 # For now don't search for DNSServiceRegister in a library - only Apple's
561 # Bonjour implementation, which is always linked, works.
562 ###############################################################
564 bonjouropt = get_option('bonjour')
565 bonjour = not_found_dep
566 if cc.check_header('dns_sd.h', required: bonjouropt,
567 args: test_c_args, include_directories: postgres_inc) and \
568 cc.has_function('DNSServiceRegister',
569 args: test_c_args, include_directories: postgres_inc)
570 cdata.set('USE_BONJOUR', 1)
571 bonjour = declare_dependency()
576 ###############################################################
577 # Option: docs in HTML and man page format
578 ###############################################################
580 docs_opt = get_option('docs')
581 docs_dep = not_found_dep
582 if not docs_opt.disabled()
583 if xmllint_bin.found() and xsltproc_bin.found()
584 docs_dep = declare_dependency()
585 elif docs_opt.enabled()
586 error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
592 ###############################################################
593 # Option: docs in PDF format
594 ###############################################################
596 docs_pdf_opt = get_option('docs_pdf')
597 docs_pdf_dep = not_found_dep
598 if not docs_pdf_opt.disabled()
599 fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
600 if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
601 docs_pdf_dep = declare_dependency()
602 elif docs_pdf_opt.enabled()
603 error('missing required tools for docs in PDF format')
609 ###############################################################
611 ###############################################################
613 gssapiopt = get_option('gssapi')
616 if not gssapiopt.disabled()
617 gssapi = dependency('krb5-gssapi', required: false)
618 have_gssapi = gssapi.found()
621 gssapi_deps = [gssapi]
623 # Hardcoded lookup for gssapi. This is necessary as gssapi on windows does
624 # not install neither pkg-config nor cmake dependency information.
625 if host_system == 'windows'
626 is_64 = cc.sizeof('void *', args: test_c_args) == 8
628 gssapi_search_libs = ['gssapi64', 'krb5_64', 'comerr64']
630 gssapi_search_libs = ['gssapi32', 'krb5_32', 'comerr32']
633 gssapi_search_libs = ['gssapi_krb5']
637 foreach libname : gssapi_search_libs
638 lib = cc.find_library(libname, dirs: test_lib_d, required: false)
646 # Meson before 0.57.0 did not support using check_header() etc with
647 # declare_dependency(). Thus the tests below use the library looked up
648 # above. Once we require a newer meson version, we can simplify.
649 gssapi = declare_dependency(dependencies: gssapi_deps)
654 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi_deps, required: false,
655 args: test_c_args, include_directories: postgres_inc)
656 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
657 elif cc.check_header('gssapi.h', dependencies: gssapi_deps, required: gssapiopt,
658 args: test_c_args, include_directories: postgres_inc)
659 cdata.set('HAVE_GSSAPI_H', 1)
665 elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi_deps, required: false,
666 args: test_c_args, include_directories: postgres_inc)
667 cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
668 elif cc.check_header('gssapi_ext.h', dependencies: gssapi_deps, required: gssapiopt,
669 args: test_c_args, include_directories: postgres_inc)
670 cdata.set('HAVE_GSSAPI_EXT_H', 1)
676 elif cc.has_function('gss_store_cred_into', dependencies: gssapi_deps,
677 args: test_c_args, include_directories: postgres_inc)
678 cdata.set('ENABLE_GSS', 1)
680 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
681 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
682 elif gssapiopt.enabled()
683 error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
688 if not have_gssapi and gssapiopt.enabled()
689 error('dependency lookup for gssapi failed')
694 gssapi = not_found_dep
699 ###############################################################
701 ###############################################################
703 ldapopt = get_option('ldap')
704 if ldapopt.disabled()
706 ldap_r = not_found_dep
707 elif host_system == 'windows'
708 ldap = cc.find_library('wldap32', required: ldapopt)
711 # macos framework dependency is buggy for ldap (one can argue whether it's
712 # Apple's or meson's fault), leading to an endless recursion with ldap.h
713 # including itself. See https://github.com/mesonbuild/meson/issues/10002
714 # Luckily we only need pkg-config support, so the workaround isn't
716 ldap = dependency('ldap', method: 'pkg-config', required: false)
719 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
722 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
723 has_headers: 'ldap.h', header_include_directories: postgres_inc)
725 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
726 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
727 # library from a separate OpenLDAP installation). The most reliable
728 # way to check that is to check for a function introduced in 2.5.
730 # don't have ldap, we shouldn't check for ldap_r
731 elif cc.has_function('ldap_verify_credentials',
732 dependencies: ldap, args: test_c_args)
733 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
736 # Use ldap_r for FE if available, else assume ldap is thread-safe.
737 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
738 has_headers: 'ldap.h', header_include_directories: postgres_inc)
739 if not ldap_r.found()
742 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
743 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
746 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
747 # process. Check for OpenLDAP versions known not to tolerate doing so;
748 # assume non-OpenLDAP implementations are safe. The dblink test suite
749 # exercises the hazardous interaction directly.
750 compat_test_code = '''
752 #if !defined(LDAP_VENDOR_VERSION) || \
753 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
754 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
758 if not cc.compiles(compat_test_code,
759 name: 'LDAP implementation compatible',
760 dependencies: ldap, args: test_c_args)
762 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
763 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
764 *** also uses LDAP will crash on exit.''')
769 if ldap.found() and cc.has_function('ldap_initialize',
770 dependencies: ldap, args: test_c_args)
771 cdata.set('HAVE_LDAP_INITIALIZE', 1)
776 assert(ldap_r.found())
777 cdata.set('USE_LDAP', 1)
779 assert(not ldap_r.found())
784 ###############################################################
786 ###############################################################
788 llvmopt = get_option('llvm')
790 if add_languages('cpp', required: llvmopt, native: false)
791 llvm = dependency('llvm', version: '>=10', method: 'config-tool', required: llvmopt)
795 cdata.set('USE_LLVM', 1)
797 cpp = meson.get_compiler('cpp')
799 llvm_binpath = llvm.get_variable(configtool: 'bindir')
801 ccache = find_program('ccache', native: true, required: false)
803 # Some distros put LLVM and clang in different paths, so fallback to
804 # find via PATH, too.
805 clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
808 message('llvm requires a C++ compiler')
813 ###############################################################
815 ###############################################################
817 icuopt = get_option('icu')
818 if not icuopt.disabled()
819 icu = dependency('icu-uc', required: false)
821 icu_i18n = dependency('icu-i18n', required: true)
824 # Unfortunately the dependency is named differently with cmake
825 if not icu.found() # combine with above once meson 0.60.0 is required
826 icu = dependency('ICU', required: icuopt,
827 components: ['uc'], modules: ['ICU::uc'], method: 'cmake')
829 icu_i18n = dependency('ICU', required: true,
830 components: ['i18n'], modules: ['ICU::i18n'])
835 cdata.set('USE_ICU', 1)
837 icu_i18n = not_found_dep
842 icu_i18n = not_found_dep
847 ###############################################################
849 ###############################################################
851 libxmlopt = get_option('libxml')
852 if not libxmlopt.disabled()
853 libxml = dependency('libxml-2.0', required: false, version: '>= 2.6.23')
854 # Unfortunately the dependency is named differently with cmake
855 if not libxml.found() # combine with above once meson 0.60.0 is required
856 libxml = dependency('LibXml2', required: libxmlopt, version: '>= 2.6.23',
861 cdata.set('USE_LIBXML', 1)
864 libxml = not_found_dep
869 ###############################################################
871 ###############################################################
873 libxsltopt = get_option('libxslt')
874 if not libxsltopt.disabled()
875 libxslt = dependency('libxslt', required: false)
876 # Unfortunately the dependency is named differently with cmake
877 if not libxslt.found() # combine with above once meson 0.60.0 is required
878 libxslt = dependency('LibXslt', required: libxsltopt, method: 'cmake')
882 cdata.set('USE_LIBXSLT', 1)
885 libxslt = not_found_dep
890 ###############################################################
892 ###############################################################
894 lz4opt = get_option('lz4')
895 if not lz4opt.disabled()
896 lz4 = dependency('liblz4', required: false)
897 # Unfortunately the dependency is named differently with cmake
898 if not lz4.found() # combine with above once meson 0.60.0 is required
899 lz4 = dependency('lz4', required: lz4opt,
900 method: 'cmake', modules: ['LZ4::lz4_shared'],
905 cdata.set('USE_LZ4', 1)
906 cdata.set('HAVE_LIBLZ4', 1)
915 ###############################################################
916 # Library: Tcl (for pltcl)
918 # NB: tclConfig.sh is used in autoconf build for getting
919 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
920 # variables. For now we have not seen a need to copy
921 # that behaviour to the meson build.
922 ###############################################################
924 tclopt = get_option('pltcl')
925 tcl_version = get_option('tcl_version')
926 tcl_dep = not_found_dep
927 if not tclopt.disabled()
930 tcl_dep = dependency(tcl_version, required: false)
932 if not tcl_dep.found()
933 tcl_dep = cc.find_library(tcl_version,
938 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
939 tcl_dep = not_found_dep
945 ###############################################################
947 ###############################################################
949 pamopt = get_option('pam')
950 if not pamopt.disabled()
951 pam = dependency('pam', required: false)
954 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
958 pam_header_found = false
960 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
961 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
962 args: test_c_args, include_directories: postgres_inc)
963 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
964 pam_header_found = true
965 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
966 args: test_c_args, include_directories: postgres_inc)
967 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
968 pam_header_found = true
972 cdata.set('USE_PAM', 1)
983 ###############################################################
984 # Library: Perl (for plperl)
985 ###############################################################
987 perlopt = get_option('plperl')
988 perl_dep = not_found_dep
989 if not perlopt.disabled()
992 # First verify that perl has the necessary dependencies installed
993 perl_mods = run_command(
995 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
998 if perl_mods.returncode() != 0
999 perl_may_work = false
1000 perl_msg = 'perl installation does not have the required modules'
1003 # Then inquire perl about its configuration
1005 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
1006 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
1007 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
1008 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
1009 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
1011 perl_inc_dir = '@0@/CORE'.format(archlibexp)
1013 if perlversion.version_compare('< 5.14')
1014 perl_may_work = false
1015 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
1016 elif useshrplib != 'true'
1017 perl_may_work = false
1018 perl_msg = 'need a shared perl'
1023 # On most platforms, archlibexp is also where the Perl include files live ...
1024 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
1025 # ... but on newer macOS versions, we must use -iwithsysroot to look
1027 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
1028 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
1029 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
1032 # check compiler finds header
1033 if not cc.has_header('perl.h', required: false,
1034 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
1035 perl_may_work = false
1036 perl_msg = 'missing perl.h'
1041 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
1043 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
1044 foreach flag : perl_ccflags_r.split(' ')
1045 if flag.startswith('-D') and \
1046 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
1047 perl_ccflags += flag
1051 if host_system == 'windows'
1052 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
1054 if cc.get_id() == 'msvc'
1055 # prevent binary mismatch between MSVC built plperl and Strawberry or
1056 # msys ucrt perl libraries
1057 perl_v = run_command(perl, '-V').stdout()
1058 if not perl_v.contains('USE_THREAD_SAFE_LOCALE')
1059 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
1064 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
1065 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
1067 # We are after Embed's ldopts, but without the subset mentioned in
1068 # Config's ccdlflags and ldflags. (Those are the choices of those who
1069 # built the Perl installation, which are not necessarily appropriate
1070 # for building PostgreSQL.)
1071 perl_ldopts = run_command(perl, '-e', '''
1072 use ExtUtils::Embed;
1073 use Text::ParseWords;
1074 # tell perl to suppress including these in ldopts
1075 *ExtUtils::Embed::_ldflags =*ExtUtils::Embed::_ccdlflags = sub { return ""; };
1076 # adding an argument to ldopts makes it return a value instead of printing
1077 # print one of these per line so splitting will preserve spaces in file names.
1078 # shellwords eats backslashes, so we need to escape them.
1079 (my $opts = ldopts(undef)) =~ s!\\!\\\\!g;
1080 print "$_\n" foreach shellwords($opts);
1082 check: true).stdout().strip().split('\n')
1084 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1086 perl_dep_int = declare_dependency(
1087 compile_args: perl_ccflags,
1088 link_args: perl_ldopts,
1089 version: perlversion,
1092 # While we're at it, check that we can link to libperl.
1093 # On most platforms, if perl.h is there then libperl.so will be too, but
1094 # at this writing Debian packages them separately.
1095 perl_link_test = '''
1098 #define __inline__ inline
1106 if not cc.links(perl_link_test, name: 'libperl',
1107 args: test_c_args + perl_ccflags + perl_ldopts,
1108 include_directories: postgres_inc)
1109 perl_may_work = false
1110 perl_msg = 'missing libperl'
1113 endif # perl_may_work
1116 perl_dep = perl_dep_int
1118 if perlopt.enabled()
1119 error('dependency plperl failed: @0@'.format(perl_msg))
1121 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1128 ###############################################################
1129 # Library: Python (for plpython)
1130 ###############################################################
1132 pyopt = get_option('plpython')
1133 python3_dep = not_found_dep
1134 if not pyopt.disabled()
1135 pm = import('python')
1136 python3_inst = pm.find_installation(python.path(), required: pyopt)
1137 if python3_inst.found()
1138 python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1139 # Remove this check after we depend on Meson >= 1.1.0
1140 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1141 python3_dep = not_found_dep
1148 ###############################################################
1150 ###############################################################
1152 if not get_option('readline').disabled()
1153 libedit_preferred = get_option('libedit_preferred')
1154 # Set the order of readline dependencies.
1155 # cc.find_library breaks and throws on the first dependency which
1156 # is marked as required=true and can't be found. Thus, we only mark
1157 # the last dependency to look up as required, to not throw too early.
1158 check_readline_deps = [
1160 'name': libedit_preferred ? 'libedit' : 'readline',
1164 'name': libedit_preferred ? 'readline' : 'libedit',
1165 'required': get_option('readline')
1169 foreach readline_dep : check_readline_deps
1170 readline = dependency(readline_dep['name'], required: false)
1171 if not readline.found()
1172 readline = cc.find_library(readline_dep['name'],
1173 required: readline_dep['required'],
1182 cdata.set('HAVE_LIBREADLINE', 1)
1185 'header_prefix': 'editline/',
1186 'flag_prefix': 'EDITLINE_',
1189 'header_prefix': 'readline/',
1190 'flag_prefix': 'READLINE_',
1193 'header_prefix': '',
1197 # Set the order of prefixes
1198 prefixes = libedit_preferred ? \
1199 [editline_prefix, default_prefix, readline_prefix] : \
1200 [readline_prefix, default_prefix, editline_prefix]
1202 at_least_one_header_found = false
1203 foreach header : ['history', 'readline']
1205 foreach prefix : prefixes
1206 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1207 # Check history.h and readline.h
1208 if not is_found and cc.has_header(header_file,
1209 args: test_c_args, include_directories: postgres_inc,
1210 dependencies: [readline], required: false)
1211 if header == 'readline'
1212 readline_h = header_file
1214 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1216 at_least_one_header_found = true
1221 if not at_least_one_header_found
1222 error('''readline header not found
1223 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1224 failure. It is possible the compiler isn't looking in the proper directory.
1225 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1230 'history_truncate_file',
1231 'rl_completion_matches',
1232 'rl_filename_completion_function',
1233 'rl_reset_screen_size',
1237 foreach func : check_funcs
1238 found = cc.has_function(func, dependencies: [readline],
1239 args: test_c_args, include_directories: postgres_inc)
1240 cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1244 'rl_completion_suppress_quote',
1245 'rl_filename_quote_characters',
1246 'rl_filename_quoting_function',
1249 foreach var : check_vars
1250 cdata.set('HAVE_' + var.to_upper(),
1251 cc.has_header_symbol(readline_h, var,
1252 args: test_c_args, include_directories: postgres_inc,
1253 prefix: '#include <stdio.h>',
1254 dependencies: [readline]) ? 1 : false)
1257 # If found via cc.find_library() ensure headers are found when using the
1258 # dependency. On meson < 0.57 one cannot do compiler checks using the
1259 # dependency returned by declare_dependency(), so we can't do this above.
1260 if readline.type_name() == 'library'
1261 readline = declare_dependency(dependencies: readline,
1262 include_directories: postgres_inc)
1265 # On windows with mingw readline requires auto-import to successfully
1266 # link, as the headers don't use declspec(dllimport)
1267 if host_system == 'windows' and cc.get_id() != 'msvc'
1268 readline = declare_dependency(dependencies: readline,
1269 link_args: '-Wl,--enable-auto-import')
1273 # XXX: Figure out whether to implement mingw warning equivalent
1275 readline = not_found_dep
1280 ###############################################################
1282 ###############################################################
1284 selinux = not_found_dep
1285 selinuxopt = get_option('selinux')
1286 if meson.version().version_compare('>=0.59')
1287 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1289 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1290 cdata.set('HAVE_LIBSELINUX',
1291 selinux.found() ? 1 : false)
1295 ###############################################################
1297 ###############################################################
1299 systemd = not_found_dep
1300 systemdopt = get_option('systemd')
1301 if meson.version().version_compare('>=0.59')
1302 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1304 systemd = dependency('libsystemd', required: systemdopt)
1305 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1309 ###############################################################
1311 ###############################################################
1314 ssl_library = 'none'
1315 sslopt = get_option('ssl')
1317 if sslopt == 'auto' and auto_features.disabled()
1321 if sslopt in ['auto', 'openssl']
1322 openssl_required = (sslopt == 'openssl')
1324 # Try to find openssl via pkg-config et al, if that doesn't work
1325 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1326 # the library names that we know about.
1328 # via pkg-config et al
1329 ssl = dependency('openssl', required: false)
1330 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1331 # we pass cc.find_library() results if necessary
1334 # via library + headers
1336 ssl_lib = cc.find_library('ssl',
1338 header_include_directories: postgres_inc,
1339 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1340 required: openssl_required)
1341 crypto_lib = cc.find_library('crypto',
1343 required: openssl_required)
1344 if ssl_lib.found() and crypto_lib.found()
1345 ssl_int = [ssl_lib, crypto_lib]
1346 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1348 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1349 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1357 ['CRYPTO_new_ex_data', {'required': true}],
1358 ['SSL_new', {'required': true}],
1360 # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1361 ['SSL_CTX_set_cert_cb'],
1363 # Functions introduced in OpenSSL 1.1.0. We used to check for
1364 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1365 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1366 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1368 ['OPENSSL_init_ssl'],
1370 ['ASN1_STRING_get0_data'],
1374 # OpenSSL versions before 1.1.0 required setting callback functions, for
1375 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1376 # function was removed.
1379 # Function introduced in OpenSSL 1.1.1
1380 ['X509_get_signature_info'],
1381 ['SSL_CTX_set_num_tickets'],
1384 are_openssl_funcs_complete = true
1385 foreach c : check_funcs
1387 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1388 required = c.get(1, {}).get('required', false)
1389 if required and not val
1390 are_openssl_funcs_complete = false
1392 error('openssl function @0@ is required'.format(func))
1396 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1400 if are_openssl_funcs_complete
1401 cdata.set('USE_OPENSSL', 1,
1402 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1403 cdata.set('OPENSSL_API_COMPAT', '0x10002000L',
1404 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1405 ssl_library = 'openssl'
1412 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1413 error('no SSL library found')
1418 ###############################################################
1420 ###############################################################
1422 uuidopt = get_option('uuid')
1423 if uuidopt != 'none'
1424 uuidname = uuidopt.to_upper()
1425 if uuidopt == 'e2fs'
1426 uuid = dependency('uuid', required: true)
1427 uuidfunc = 'uuid_generate'
1428 uuidheader = 'uuid/uuid.h'
1429 elif uuidopt == 'bsd'
1430 # libc should have uuid function
1431 uuid = declare_dependency()
1432 uuidfunc = 'uuid_to_string'
1433 uuidheader = 'uuid.h'
1434 elif uuidopt == 'ossp'
1435 # In upstream, the package and library is called just 'uuid', but many
1436 # distros change it to 'ossp-uuid'.
1437 uuid = dependency('ossp-uuid', 'uuid', required: false)
1438 uuidfunc = 'uuid_export'
1439 uuidheader = 'uuid.h'
1441 # Hardcoded lookup for ossp-uuid. This is necessary as ossp-uuid on
1442 # windows installs neither a pkg-config nor a cmake dependency
1443 # information. Nor is there another supported uuid implementation
1444 # available on windows.
1446 uuid = cc.find_library('ossp-uuid',
1447 required: false, dirs: test_lib_d,
1448 has_headers: uuidheader, header_include_directories: postgres_inc)
1451 uuid = cc.find_library('uuid',
1452 required: true, dirs: test_lib_d,
1453 has_headers: uuidheader, header_include_directories: postgres_inc)
1456 error('unknown uuid build option value: @0@'.format(uuidopt))
1459 if not cc.has_header_symbol(uuidheader, uuidfunc,
1461 include_directories: postgres_inc,
1463 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1465 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1467 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1468 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1470 uuid = not_found_dep
1475 ###############################################################
1477 ###############################################################
1479 zlibopt = get_option('zlib')
1480 zlib = not_found_dep
1481 if not zlibopt.disabled()
1482 zlib_t = dependency('zlib', required: zlibopt)
1484 if zlib_t.type_name() == 'internal'
1485 # if fallback was used, we don't need to test if headers are present (they
1486 # aren't built yet, so we can't test)
1488 elif not zlib_t.found()
1489 warning('did not find zlib')
1490 elif not cc.has_header('zlib.h',
1491 args: test_c_args, include_directories: postgres_inc,
1492 dependencies: [zlib_t], required: zlibopt)
1493 warning('zlib header not found')
1499 cdata.set('HAVE_LIBZ', 1)
1505 ###############################################################
1506 # Library: tap test dependencies
1507 ###############################################################
1509 # Check whether tap tests are enabled or not
1510 tap_tests_enabled = false
1511 tapopt = get_option('tap_tests')
1512 if not tapopt.disabled()
1513 # Checking for perl modules for tap tests
1514 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1515 if perl_ipc_run_check.returncode() != 0
1516 message(perl_ipc_run_check.stderr().strip())
1518 error('Additional Perl modules are required to run TAP tests.')
1520 warning('Additional Perl modules are required to run TAP tests.')
1523 tap_tests_enabled = true
1529 ###############################################################
1531 ###############################################################
1533 zstdopt = get_option('zstd')
1534 if not zstdopt.disabled()
1535 zstd = dependency('libzstd', required: false, version: '>=1.4.0')
1536 # Unfortunately the dependency is named differently with cmake
1537 if not zstd.found() # combine with above once meson 0.60.0 is required
1538 zstd = dependency('zstd', required: zstdopt, version: '>=1.4.0',
1539 method: 'cmake', modules: ['zstd::libzstd_shared'])
1543 cdata.set('USE_ZSTD', 1)
1544 cdata.set('HAVE_LIBZSTD', 1)
1548 zstd = not_found_dep
1553 ###############################################################
1555 ###############################################################
1557 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1558 # unnecessarily, because we optionally rely on newer features.
1560 #include <stdbool.h>
1561 #include <complex.h>
1563 #include <inttypes.h>
1565 struct named_init_test {
1570 extern void structfunc(struct named_init_test);
1572 int main(int argc, char **argv)
1574 struct named_init_test nit = {
1579 for (int loop_var = 0; loop_var < 3; loop_var++)
1584 structfunc((struct named_init_test){1, 0});
1590 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1591 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1592 args: test_c_args + ['-std=c99'])
1593 test_c_args += '-std=c99'
1594 cflags += '-std=c99'
1596 error('C compiler does not support C99')
1600 sizeof_long = cc.sizeof('long', args: test_c_args)
1601 cdata.set('SIZEOF_LONG', sizeof_long)
1603 cdata.set('HAVE_LONG_INT_64', 1)
1604 pg_int64_type = 'long int'
1605 cdata.set_quoted('INT64_MODIFIER', 'l')
1606 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1607 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1608 pg_int64_type = 'long long int'
1609 cdata.set_quoted('INT64_MODIFIER', 'll')
1611 error('do not know how to get a 64bit int')
1613 cdata.set('PG_INT64_TYPE', pg_int64_type)
1615 if host_machine.endian() == 'big'
1616 cdata.set('WORDS_BIGENDIAN', 1)
1619 # Determine memory alignment requirements for the basic C data types.
1621 alignof_types = ['short', 'int', 'long', 'double']
1622 foreach t : alignof_types
1623 align = cc.alignment(t, args: test_c_args)
1624 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1627 # Compute maximum alignment of any basic type.
1629 # We require 'double' to have the strictest alignment among the basic types,
1630 # because otherwise the C ABI might impose 8-byte alignment on some of the
1631 # other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
1632 # cause a mismatch between the tuple layout and the C struct layout of a
1633 # catalog tuple. We used to carefully order catalog columns such that any
1634 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1635 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1636 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1638 # We assume without checking that int64's alignment is at least as strong
1639 # as long, char, short, or int. Note that we intentionally do not consider
1640 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1641 # would be too much of a penalty for disk and memory space.
1642 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1643 if cc.alignment(pg_int64_type, args: test_c_args) > alignof_double
1644 error('alignment of int64 is greater than the alignment of double')
1646 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1648 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1649 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1652 # Check if __int128 is a working 128 bit integer type, and if so
1653 # define PG_INT128_TYPE to that typename.
1655 # This currently only detects a GCC/clang extension, but support for other
1656 # environments may be added in the future.
1658 # For the moment we only test for support for 128bit math; support for
1659 # 128bit literals and snprintf is not required.
1662 * We don't actually run this test, just link it to verify that any support
1663 * functions needed for __int128 are present.
1665 * These are globals to discourage the compiler from folding all the
1666 * arithmetic tests down to compile-time constants. We do not have
1667 * convenient support for 128bit literals at this point...
1669 __int128 a = 48828125;
1670 __int128 b = 97656250;
1675 a = (a << 12) + 1; /* 200000000001 */
1676 b = (b << 12) + 5; /* 400000000005 */
1677 /* try the most relevant arithmetic ops */
1680 /* must use the results, else compiler may optimize arithmetic away */
1686 buggy_int128 = false
1688 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1689 # If not cross-compiling, we can test for bugs and disable use of __int128
1690 # with buggy compilers. If cross-compiling, hope for the best.
1691 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1692 if not meson.is_cross_build()
1694 /* This must match the corresponding code in c.h: */
1695 #if defined(__GNUC__) || defined(__SUNPRO_C)
1696 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1697 #elif defined(_MSC_VER)
1698 #define pg_attribute_aligned(a) __declspec(align(a))
1700 typedef __int128 int128a
1701 #if defined(pg_attribute_aligned)
1702 pg_attribute_aligned(8)
1707 void pass_by_val(void *buffer, int128a par) { holder = par; }
1711 long int i64 = 97656225L << 12;
1713 pass_by_val(main, (int128a) i64);
1717 name: '__int128 alignment bug',
1719 assert(r.compiled())
1720 if r.returncode() != 0
1722 message('__int128 support present but buggy and thus disabled')
1727 cdata.set('PG_INT128_TYPE', '__int128')
1728 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1733 # Check if the C compiler knows computed gotos (gcc extension, also
1734 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1736 # Checking whether computed gotos are supported syntax-wise ought to
1737 # be enough, as the syntax is otherwise illegal.
1739 static inline int foo(void)
1741 void *labeladdrs[] = {&&my_label};
1742 goto *labeladdrs[0];
1747 cdata.set('HAVE_COMPUTED_GOTO', 1)
1751 # Check if the C compiler understands _Static_assert(),
1752 # and define HAVE__STATIC_ASSERT if so.
1754 # We actually check the syntax ({ _Static_assert(...) }), because we need
1755 # gcc-style compound expressions to be able to wrap the thing into macros.
1757 int main(int arg, char **argv)
1759 ({ _Static_assert(1, "foo"); });
1763 cdata.set('HAVE__STATIC_ASSERT', 1)
1767 # We use <stdbool.h> if we have it and it declares type bool as having
1768 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1769 if cc.has_type('_Bool', args: test_c_args) \
1770 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1771 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1772 cdata.set('HAVE__BOOL', 1)
1773 cdata.set('PG_USE_STDBOOL', 1)
1777 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1778 # warning for each use of %m.
1779 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1781 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1782 static void call_log(void)
1784 emit_log(0, "error: %s: %m", "foo");
1787 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1788 foreach a : printf_attributes
1789 if cc.compiles(testsrc.format(a),
1790 args: test_c_args + attrib_error_args, name: 'format ' + a)
1791 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1797 if cc.has_function_attribute('visibility:default') and \
1798 cc.has_function_attribute('visibility:hidden')
1799 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1801 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1802 # inlineshidden to C code as well... And either way, we want to put these
1803 # flags into exported files (pgxs, .pc files).
1804 cflags_mod += '-fvisibility=hidden'
1805 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1806 ldflags_mod += '-fvisibility=hidden'
1810 # Check if various builtins exist. Some builtins are tested separately,
1811 # because we want to test something more complicated than the generic case.
1824 foreach builtin : builtins
1825 fname = '__builtin_@0@'.format(builtin)
1826 if cc.has_function(fname, args: test_c_args)
1827 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1832 # Check if the C compiler understands __builtin_types_compatible_p,
1833 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1835 # We check usage with __typeof__, though it's unlikely any compiler would
1836 # have the former and not the latter.
1839 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1841 name: '__builtin_types_compatible_p',
1843 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1847 # Check if the C compiler understands __builtin_$op_overflow(),
1848 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1850 # Check for the most complicated case, 64 bit multiplication, as a
1851 # proxy for all of the operations. To detect the case where the compiler
1852 # knows the function but library support is missing, we must link not just
1853 # compile, and store the results in global variables so the compiler doesn't
1854 # optimize away the call.
1862 return __builtin_mul_overflow(a, b, &result);
1864 name: '__builtin_mul_overflow',
1865 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1867 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1871 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1872 # here. To prevent problems due to two detection methods working, stop
1873 # checking after one.
1876 int main(int arg, char **argv)
1878 unsigned int exx[4] = {0, 0, 0, 0};
1879 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1881 ''', name: '__get_cpuid',
1883 cdata.set('HAVE__GET_CPUID', 1)
1886 int main(int arg, char **argv)
1888 unsigned int exx[4] = {0, 0, 0, 0};
1891 ''', name: '__cpuid',
1893 cdata.set('HAVE__CPUID', 1)
1897 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1900 int main(int arg, char **argv)
1902 unsigned int exx[4] = {0, 0, 0, 0};
1903 __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1905 ''', name: '__get_cpuid_count',
1907 cdata.set('HAVE__GET_CPUID_COUNT', 1)
1910 int main(int arg, char **argv)
1912 unsigned int exx[4] = {0, 0, 0, 0};
1913 __cpuidex(exx, 7, 0);
1915 ''', name: '__cpuidex',
1917 cdata.set('HAVE__CPUIDEX', 1)
1921 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1922 # versions of clang do not understand -fexcess-precision=standard, the use of
1923 # x87 floating point operations leads to problems like isinf possibly returning
1924 # false for a value that is infinite when converted from the 80bit register to
1925 # the 8byte memory representation.
1927 # Only perform the test if the compiler doesn't understand
1928 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1930 if '-fexcess-precision=standard' not in cflags
1931 if not cc.compiles('''
1932 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1935 name: '', args: test_c_args)
1936 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1942 ###############################################################
1944 ###############################################################
1946 common_functional_flags = [
1947 # Disable strict-aliasing rules; needed for gcc 3.3+
1948 '-fno-strict-aliasing',
1949 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1951 '-fexcess-precision=standard',
1954 cflags += cc.get_supported_arguments(common_functional_flags)
1956 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1959 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1960 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1962 common_warning_flags = [
1963 '-Wmissing-prototypes',
1965 # Really don't want VLAs to be used in our dialect of C
1967 # On macOS, complain about usage of symbols newer than the deployment target
1968 '-Werror=unguarded-availability-new',
1970 '-Wmissing-format-attribute',
1971 '-Wimplicit-fallthrough=3',
1972 '-Wcast-function-type',
1973 '-Wshadow=compatible-local',
1974 # This was included in -Wall/-Wformat in older GCC versions
1975 '-Wformat-security',
1978 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1980 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1983 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1984 # the result for them
1985 cflags_no_decl_after_statement = []
1986 if cc.has_argument('-Wdeclaration-after-statement')
1987 cflags_warn += '-Wdeclaration-after-statement'
1988 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1992 # The following tests want to suppress various unhelpful warnings by adding
1993 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1994 # switches, so we have to test for the positive form and if that works,
1995 # add the negative form.
1997 negative_warning_flags = [
1998 # Suppress clang's unhelpful unused-command-line-argument warnings.
1999 'unused-command-line-argument',
2001 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
2002 # of warnings when building plperl because of usages in the Perl headers.
2003 'compound-token-split-by-macro',
2005 # Similarly disable useless truncation warnings from gcc 8+
2006 'format-truncation',
2007 'stringop-truncation',
2009 # Suppress clang 16's strict warnings about function casts
2010 'cast-function-type-strict',
2012 # To make warning_level=2 / -Wextra work, we'd need at least the following
2014 # 'missing-field-initializers',
2016 # 'unused-parameter',
2019 foreach w : negative_warning_flags
2020 if cc.has_argument('-W' + w)
2021 cflags_warn += '-Wno-' + w
2023 if llvm.found() and cpp.has_argument('-W' + w)
2024 cxxflags_warn += '-Wno-' + w
2029 if cc.get_id() == 'msvc'
2031 '/wd4018', # signed/unsigned mismatch
2032 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
2033 '/wd4273', # inconsistent DLL linkage
2034 '/wd4101', # unreferenced local variable
2035 '/wd4102', # unreferenced label
2036 '/wd4090', # different 'modifier' qualifiers
2037 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
2045 '/D_CRT_SECURE_NO_DEPRECATE',
2046 '/D_CRT_NONSTDC_NO_DEPRECATE',
2049 # We never need export libraries. As link.exe reports their creation, they
2050 # are unnecessarily noisy. Similarly, we don't need import library for
2051 # modules, we only import them dynamically, and they're also noisy.
2053 ldflags_mod += '/NOIMPLIB'
2057 # Compute flags that are built into Meson. We need these to
2058 # substitute into Makefile.global and for pg_config. We only compute
2059 # the flags for Unix-style compilers, since that's the only style that
2060 # would use Makefile.global or pg_config.
2062 # We don't use get_option('warning_level') here, because the other
2063 # warning levels are not useful with PostgreSQL source code.
2064 common_builtin_flags = ['-Wall']
2066 if get_option('debug')
2067 common_builtin_flags += ['-g']
2070 optimization = get_option('optimization')
2071 if optimization == '0'
2072 common_builtin_flags += ['-O0']
2073 elif optimization == '1'
2074 common_builtin_flags += ['-O1']
2075 elif optimization == '2'
2076 common_builtin_flags += ['-O2']
2077 elif optimization == '3'
2078 common_builtin_flags += ['-O3']
2079 elif optimization == 's'
2080 common_builtin_flags += ['-Os']
2083 cflags_builtin = cc.get_supported_arguments(common_builtin_flags)
2085 cxxflags_builtin = cpp.get_supported_arguments(common_builtin_flags)
2090 ###############################################################
2092 ###############################################################
2094 if not get_option('spinlocks')
2095 warning('Not using spinlocks will cause poor performance')
2097 cdata.set('HAVE_SPINLOCKS', 1)
2100 if not get_option('atomics')
2101 warning('Not using atomics will cause poor performance')
2103 # XXX: perhaps we should require some atomics support in this case these
2105 cdata.set('HAVE_ATOMICS', 1)
2108 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2109 'desc': '__sync_lock_test_and_set(char)',
2112 __sync_lock_test_and_set(&lock, 1);
2113 __sync_lock_release(&lock);'''},
2115 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2116 'desc': '__sync_lock_test_and_set(int32)',
2119 __sync_lock_test_and_set(&lock, 1);
2120 __sync_lock_release(&lock);'''},
2122 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2123 'desc': '__sync_val_compare_and_swap(int32)',
2126 __sync_val_compare_and_swap(&val, 0, 37);'''},
2128 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2129 'desc': '__sync_val_compare_and_swap(int64)',
2132 __sync_val_compare_and_swap(&val, 0, 37);'''},
2134 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2135 'desc': ' __atomic_compare_exchange_n(int32)',
2139 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2141 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2142 'desc': ' __atomic_compare_exchange_n(int64)',
2146 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2149 foreach check : atomic_checks
2154 }'''.format(check['test'])
2156 cdata.set(check['name'],
2158 name: check['desc'],
2159 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
2166 ###############################################################
2167 # Check for the availability of XSAVE intrinsics.
2168 ###############################################################
2171 if host_cpu == 'x86' or host_cpu == 'x86_64'
2174 #include <immintrin.h>
2178 return _xgetbv(0) & 0xe0;
2182 if cc.links(prog, name: 'XSAVE intrinsics without -mxsave',
2184 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2185 elif cc.links(prog, name: 'XSAVE intrinsics with -mxsave',
2186 args: test_c_args + ['-mxsave'])
2187 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2188 cflags_xsave += '-mxsave'
2194 ###############################################################
2195 # Check for the availability of AVX-512 popcount intrinsics.
2196 ###############################################################
2199 if host_cpu == 'x86_64'
2202 #include <immintrin.h>
2206 const char buf[sizeof(__m512i)];
2208 __m512i accum = _mm512_setzero_si512();
2209 const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2210 const __m512i cnt = _mm512_popcnt_epi64(val);
2211 accum = _mm512_add_epi64(accum, cnt);
2212 popcnt = _mm512_reduce_add_epi64(accum);
2213 /* return computed value, to prevent the above being optimized away */
2218 if cc.links(prog, name: 'AVX-512 popcount without -mavx512vpopcntdq -mavx512bw',
2219 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))])
2220 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2221 elif cc.links(prog, name: 'AVX-512 popcount with -mavx512vpopcntdq -mavx512bw',
2222 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))] + ['-mavx512vpopcntdq'] + ['-mavx512bw'])
2223 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2224 cflags_popcnt += ['-mavx512vpopcntdq'] + ['-mavx512bw']
2230 ###############################################################
2231 # Select CRC-32C implementation.
2233 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2234 # use the special CRC instructions for calculating CRC-32C. If we're not
2235 # targeting such a processor, but we can nevertheless produce code that uses
2236 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
2237 # implementations and select which one to use at runtime, depending on whether
2238 # SSE 4.2 is supported by the processor we're running on.
2240 # Similarly, if we are targeting an ARM processor that has the CRC
2241 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2242 # we're not targeting such a processor, but can nevertheless produce code that
2243 # uses the CRC instructions, compile both, and select at runtime.
2244 ###############################################################
2246 have_optimized_crc = false
2248 if host_cpu == 'x86' or host_cpu == 'x86_64'
2250 if cc.get_id() == 'msvc'
2251 cdata.set('USE_SSE42_CRC32C', false)
2252 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2253 have_optimized_crc = true
2257 #include <nmmintrin.h>
2261 unsigned int crc = 0;
2262 crc = _mm_crc32_u8(crc, 0);
2263 crc = _mm_crc32_u32(crc, 0);
2264 /* return computed value, to prevent the above being optimized away */
2269 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2271 # Use Intel SSE 4.2 unconditionally.
2272 cdata.set('USE_SSE42_CRC32C', 1)
2273 have_optimized_crc = true
2274 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2275 args: test_c_args + ['-msse4.2'])
2276 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2277 # the runtime check.
2278 cflags_crc += '-msse4.2'
2279 cdata.set('USE_SSE42_CRC32C', false)
2280 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2281 have_optimized_crc = true
2286 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2289 #include <arm_acle.h>
2293 unsigned int crc = 0;
2294 crc = __crc32cb(crc, 0);
2295 crc = __crc32ch(crc, 0);
2296 crc = __crc32cw(crc, 0);
2297 crc = __crc32cd(crc, 0);
2299 /* return computed value, to prevent the above being optimized away */
2304 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2306 # Use ARM CRC Extension unconditionally
2307 cdata.set('USE_ARMV8_CRC32C', 1)
2308 have_optimized_crc = true
2309 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2310 args: test_c_args + ['-march=armv8-a+crc'])
2311 # Use ARM CRC Extension, with runtime check
2312 cflags_crc += '-march=armv8-a+crc'
2313 cdata.set('USE_ARMV8_CRC32C', false)
2314 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2315 have_optimized_crc = true
2318 elif host_cpu == 'loongarch64'
2323 unsigned int crc = 0;
2324 crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2325 crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2326 crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2327 crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2329 /* return computed value, to prevent the above being optimized away */
2334 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',
2336 # Use LoongArch CRC instruction unconditionally
2337 cdata.set('USE_LOONGARCH_CRC32C', 1)
2338 have_optimized_crc = true
2343 if not have_optimized_crc
2344 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2346 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2351 ###############################################################
2352 # Other CPU specific stuff
2353 ###############################################################
2355 if host_cpu == 'x86_64'
2360 long long x = 1; long long r;
2361 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2363 name: '@0@: popcntq instruction'.format(host_cpu),
2365 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2368 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2369 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2370 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2373 addi(int ra, int si)
2376 if (__builtin_constant_p(si))
2377 __asm__ __volatile__(
2378 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2381 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2384 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2391 ###############################################################
2392 # Library / OS tests
2393 ###############################################################
2395 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2396 # unnecessary checks over and over, particularly on windows.
2410 'sys/personality.h',
2419 foreach header : header_checks
2420 varname = 'HAVE_' + header.underscorify().to_upper()
2422 # Emulate autoconf behaviour of not-found->undef, found->1
2423 found = cc.has_header(header,
2424 include_directories: postgres_inc, args: test_c_args)
2425 cdata.set(varname, found ? 1 : false,
2426 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2431 ['F_FULLFSYNC', 'fcntl.h'],
2432 ['fdatasync', 'unistd.h'],
2433 ['posix_fadvise', 'fcntl.h'],
2434 ['strlcat', 'string.h'],
2435 ['strlcpy', 'string.h'],
2436 ['strnlen', 'string.h'],
2439 # Need to check for function declarations for these functions, because
2440 # checking for library symbols wouldn't handle deployment target
2441 # restrictions on macOS
2443 ['preadv', 'sys/uio.h'],
2444 ['pwritev', 'sys/uio.h'],
2447 # Check presence of some optional LLVM functions.
2450 ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2451 ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2455 foreach c : decl_checks
2459 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2461 found = cc.has_header_symbol(header, func,
2462 args: test_c_args, include_directories: postgres_inc,
2464 cdata.set10(varname, found, description:
2465 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2466 don't.'''.format(func))
2470 if cc.has_type('struct option',
2471 args: test_c_args, include_directories: postgres_inc,
2472 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2473 cdata.set('HAVE_STRUCT_OPTION', 1)
2477 foreach c : ['opterr', 'optreset']
2478 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2487 '''.format(c), name: c, args: test_c_args)
2488 cdata.set(varname, 1)
2490 cdata.set(varname, false)
2494 if cc.has_type('socklen_t',
2495 args: test_c_args, include_directories: postgres_inc,
2497 #include <sys/socket.h>''')
2498 cdata.set('HAVE_SOCKLEN_T', 1)
2501 if cc.has_member('struct sockaddr', 'sa_len',
2502 args: test_c_args, include_directories: postgres_inc,
2504 #include <sys/types.h>
2505 #include <sys/socket.h>''')
2506 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2509 if cc.has_member('struct tm', 'tm_zone',
2510 args: test_c_args, include_directories: postgres_inc,
2512 #include <sys/types.h>
2515 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2520 extern int foo(void);
2523 return timezone / 60;
2526 name: 'global variable `timezone\' exists',
2527 args: test_c_args, include_directories: postgres_inc)
2528 cdata.set('HAVE_INT_TIMEZONE', 1)
2530 cdata.set('HAVE_INT_TIMEZONE', false)
2533 if cc.has_type('union semun',
2535 include_directories: postgres_inc,
2537 #include <sys/types.h>
2538 #include <sys/ipc.h>
2539 #include <sys/sem.h>
2541 cdata.set('HAVE_UNION_SEMUN', 1)
2549 switch (strerror_r(1, buf, sizeof(buf)))
2550 { case 0: break; default: break; }
2553 args: test_c_args, include_directories: postgres_inc)
2554 cdata.set('STRERROR_R_INT', 1)
2556 cdata.set('STRERROR_R_INT', false)
2559 # Find the right header file for the locale_t type. macOS needs xlocale.h;
2560 # standard is locale.h, but glibc <= 2.25 also had an xlocale.h file that
2561 # we should not use so we check the standard header first. MSVC has a
2562 # replacement defined in src/include/port/win32_port.h.
2563 if not cc.has_type('locale_t', prefix: '#include <locale.h>') and \
2564 cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2565 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2568 # Check if the C compiler understands typeof or a variant. Define
2569 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2570 foreach kw : ['typeof', '__typeof__', 'decltype']
2581 args: test_c_args, include_directories: postgres_inc)
2583 cdata.set('HAVE_TYPEOF', 1)
2585 cdata.set('typeof', kw)
2593 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2594 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2595 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2596 wcstombs_l_test = '''
2608 if (not cc.compiles(wcstombs_l_test.format(''),
2609 name: 'wcstombs_l') and
2610 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2611 name: 'wcstombs_l in xlocale.h'))
2612 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2616 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2617 # understands, because it conflicts with __declspec(restrict). Therefore we
2618 # define pg_restrict to the appropriate definition, which presumably won't
2621 # We assume C99 support, so we don't need to make this conditional.
2622 cdata.set('pg_restrict', '__restrict')
2625 # Most libraries are included only if they demonstrably provide a function we
2626 # need, but libm is an exception: always include it, because there are too
2627 # many compilers that play cute optimization games that will break probes for
2628 # standard functions such as pow().
2629 os_deps += cc.find_library('m', required: false)
2631 rt_dep = cc.find_library('rt', required: false)
2633 dl_dep = cc.find_library('dl', required: false)
2635 util_dep = cc.find_library('util', required: false)
2637 getopt_dep = cc.find_library('getopt', required: false)
2638 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2639 # Check if we want to replace getopt/getopt_long even if provided by the system
2640 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2641 # so always use our version on Windows
2642 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2643 # (i.e., allow '-' as a flag character), so use our version on those platforms
2644 # - We want to use system's getopt_long() only if the system provides struct
2646 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2647 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2650 execinfo_dep = cc.find_library('execinfo', required: false)
2652 if host_system == 'cygwin'
2653 cygipc_dep = cc.find_library('cygipc', required: false)
2655 cygipc_dep = not_found_dep
2658 if host_system == 'sunos'
2659 socket_dep = cc.find_library('socket', required: false)
2661 socket_dep = not_found_dep
2664 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2665 # unnecessary checks over and over, particularly on windows.
2667 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2668 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2669 ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2671 ['copy_file_range'],
2672 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2673 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2674 # required. Just checking for dlsym() ought to suffice.
2675 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2678 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2679 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2689 ['posix_fallocate'],
2691 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2692 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2693 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2694 ['setproctitle', {'dependencies': [util_dep]}],
2695 ['setproctitle_fast'],
2696 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2697 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2698 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2699 ['socket', {'dependencies': [socket_dep], 'define': false}],
2701 ['strerror_r', {'dependencies': [thread_dep]}],
2706 ['sync_file_range'],
2712 func_check_results = {}
2713 foreach c : func_checks
2715 kwargs = c.get(1, {})
2716 deps = kwargs.get('dependencies', [])
2718 if kwargs.get('skip', false)
2722 found = cc.has_function(func, args: test_c_args)
2729 found = cc.has_function(func, args: test_c_args,
2730 dependencies: [dep])
2738 func_check_results += {func: found}
2740 if kwargs.get('define', true)
2741 # Emulate autoconf behaviour of not-found->undef, found->1
2742 cdata.set('HAVE_' + func.underscorify().to_upper(),
2744 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2749 if cc.has_function('syslog', args: test_c_args) and \
2750 cc.check_header('syslog.h', args: test_c_args)
2751 cdata.set('HAVE_SYSLOG', 1)
2755 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2757 if sema_kind == 'unnamed_posix' and \
2758 not func_check_results.get('sem_init', false)
2762 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2763 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2765 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2766 cdata.set_quoted('DLSUFFIX', dlsuffix)
2769 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2770 cdata.set_quoted('PG_VERSION_STR',
2771 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2772 pg_version, host_machine.cpu_family(), host_system,
2773 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2778 ###############################################################
2780 ###############################################################
2782 nlsopt = get_option('nls')
2783 libintl = not_found_dep
2785 if not nlsopt.disabled()
2786 # otherwise there'd be lots of
2787 # "Gettext not found, all translation (po) targets will be ignored."
2788 # warnings if not found.
2789 msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2791 # meson 0.59 has this wrapped in dependency('intl')
2792 if (msgfmt.found() and
2793 cc.check_header('libintl.h', required: nlsopt,
2794 args: test_c_args, include_directories: postgres_inc))
2797 if cc.has_function('ngettext')
2798 libintl = declare_dependency()
2800 libintl = cc.find_library('intl',
2801 has_headers: ['libintl.h'], required: nlsopt,
2802 header_include_directories: postgres_inc,
2808 i18n = import('i18n')
2809 cdata.set('ENABLE_NLS', 1)
2815 ###############################################################
2817 ###############################################################
2819 # Set up compiler / linker arguments to be used everywhere, individual targets
2820 # can add further args directly, or indirectly via dependencies
2821 add_project_arguments(cflags, language: ['c'])
2822 add_project_arguments(cppflags, language: ['c'])
2823 add_project_arguments(cflags_warn, language: ['c'])
2824 add_project_arguments(cxxflags, language: ['cpp'])
2825 add_project_arguments(cppflags, language: ['cpp'])
2826 add_project_arguments(cxxflags_warn, language: ['cpp'])
2827 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2830 # Collect a number of lists of things while recursing through the source
2831 # tree. Later steps then can use those.
2833 # list of targets for various alias targets
2834 backend_targets = []
2837 contrib_targets = []
2838 testprep_targets = []
2842 # Define the tests to distribute them to the correct test styles later
2847 # Default options for targets
2849 # First identify rpaths
2850 bin_install_rpaths = []
2851 lib_install_rpaths = []
2852 mod_install_rpaths = []
2855 # Don't add rpaths on darwin for now - as long as only absolute references to
2856 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2857 # their final destination.
2858 if host_system != 'darwin'
2859 # Add absolute path to libdir to rpath. This ensures installed binaries /
2860 # libraries find our libraries (mainly libpq).
2861 bin_install_rpaths += dir_prefix / dir_lib
2862 lib_install_rpaths += dir_prefix / dir_lib
2863 mod_install_rpaths += dir_prefix / dir_lib
2865 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2867 # Not needed on darwin even if we use relative rpaths for our own libraries,
2868 # as the install_name of libraries in extra_lib_dirs will point to their
2870 bin_install_rpaths += postgres_lib_d
2871 lib_install_rpaths += postgres_lib_d
2872 mod_install_rpaths += postgres_lib_d
2876 # Define arguments for default targets
2878 default_target_args = {
2879 'implicit_include_directories': false,
2883 default_lib_args = default_target_args + {
2887 internal_lib_args = default_lib_args + {
2888 'build_by_default': false,
2892 default_mod_args = default_lib_args + {
2894 'install_dir': dir_lib_pkg,
2897 default_bin_args = default_target_args + {
2898 'install_dir': dir_bin,
2901 if get_option('rpath')
2902 default_lib_args += {
2903 'install_rpath': ':'.join(lib_install_rpaths),
2906 default_mod_args += {
2907 'install_rpath': ':'.join(mod_install_rpaths),
2910 default_bin_args += {
2911 'install_rpath': ':'.join(bin_install_rpaths),
2916 # Helper for exporting a limited number of symbols
2917 gen_export_kwargs = {
2918 'input': 'exports.txt',
2919 'output': '@BASENAME@.'+export_file_suffix,
2920 'command': [perl, files('src/tools/gen_export.pl'),
2921 '--format', export_file_format,
2922 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2923 'build_by_default': false,
2930 ### Helpers for custom targets used across the tree
2933 catalog_pm = files('src/backend/catalog/Catalog.pm')
2934 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2935 gen_kwlist_deps = [perfect_hash_pm]
2937 perl, '-I', '@SOURCE_ROOT@/src/tools',
2938 files('src/tools/gen_keywordlist.pl'),
2939 '--output', '@OUTDIR@', '@INPUT@']
2944 ### windows resources related stuff
2947 if host_system == 'windows'
2948 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2949 win32ver_rc = files('src/port/win32ver.rc')
2950 rcgen = find_program('src/tools/rcgen', native: true)
2953 '--srcdir', '@SOURCE_DIR@',
2954 '--builddir', meson.build_root(),
2955 '--rcout', '@OUTPUT0@',
2956 '--out', '@OUTPUT1@',
2957 '--input', '@INPUT@',
2961 if cc.get_argument_syntax() == 'msvc'
2962 rc = find_program('rc', required: true)
2963 rcgen_base_args += ['--rc', rc.path()]
2964 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2966 windres = find_program('windres', required: true)
2967 rcgen_base_args += ['--windres', windres.path()]
2968 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2971 # msbuild backend doesn't support this atm
2972 if meson.backend() == 'ninja'
2973 rcgen_base_args += ['--depfile', '@DEPFILE@']
2976 rcgen_bin_args = rcgen_base_args + [
2977 '--VFT_TYPE', 'VFT_APP',
2978 '--FILEENDING', 'exe',
2982 rcgen_lib_args = rcgen_base_args + [
2983 '--VFT_TYPE', 'VFT_DLL',
2984 '--FILEENDING', 'dll',
2987 rc_bin_gen = generator(rcgen,
2988 depfile: '@BASENAME@.d',
2989 arguments: rcgen_bin_args,
2990 output: rcgen_outputs,
2993 rc_lib_gen = generator(rcgen,
2994 depfile: '@BASENAME@.d',
2995 arguments: rcgen_lib_args,
2996 output: rcgen_outputs,
3002 # headers that the whole build tree depends on
3003 generated_headers = []
3004 # headers that the backend build depends on
3005 generated_backend_headers = []
3006 # configure_files() output, needs a way of converting to file names
3007 configure_files = []
3009 # generated files that might conflict with a partial in-tree autoconf build
3010 generated_sources = []
3011 # same, for paths that differ between autoconf / meson builds
3012 # elements are [dir, [files]]
3013 generated_sources_ac = {}
3016 # First visit src/include - all targets creating headers are defined
3017 # within. That makes it easy to add the necessary dependencies for the
3018 # subsequent build steps.
3020 subdir('src/include')
3024 # Then through src/port and src/common, as most other things depend on them
3026 frontend_port_code = declare_dependency(
3027 compile_args: ['-DFRONTEND'],
3028 include_directories: [postgres_inc],
3029 dependencies: os_deps,
3032 backend_port_code = declare_dependency(
3033 compile_args: ['-DBUILDING_DLL'],
3034 include_directories: [postgres_inc],
3035 sources: [errcodes], # errcodes.h is needed due to use of ereport
3036 dependencies: os_deps,
3041 frontend_common_code = declare_dependency(
3042 compile_args: ['-DFRONTEND'],
3043 include_directories: [postgres_inc],
3044 sources: generated_headers,
3045 dependencies: [os_deps, zlib, zstd],
3048 backend_common_code = declare_dependency(
3049 compile_args: ['-DBUILDING_DLL'],
3050 include_directories: [postgres_inc],
3051 sources: generated_headers,
3052 dependencies: [os_deps, zlib, zstd],
3055 subdir('src/common')
3057 # all shared libraries should depend on shlib_code
3058 shlib_code = declare_dependency(
3059 link_args: ldflags_sl,
3062 # all static libraries not part of the backend should depend on this
3063 frontend_stlib_code = declare_dependency(
3064 include_directories: [postgres_inc],
3065 link_with: [common_static, pgport_static],
3066 sources: generated_headers,
3067 dependencies: [os_deps, libintl],
3070 # all shared libraries not part of the backend should depend on this
3071 frontend_shlib_code = declare_dependency(
3072 include_directories: [postgres_inc],
3073 link_with: [common_shlib, pgport_shlib],
3074 sources: generated_headers,
3075 dependencies: [shlib_code, os_deps, libintl],
3078 # Dependencies both for static and shared libpq
3088 subdir('src/interfaces/libpq')
3089 # fe_utils depends on libpq
3090 subdir('src/fe_utils')
3092 # for frontend binaries
3093 frontend_code = declare_dependency(
3094 include_directories: [postgres_inc],
3095 link_with: [fe_utils, common_static, pgport_static],
3096 sources: generated_headers,
3097 dependencies: [os_deps, libintl],
3100 backend_both_deps += [
3117 backend_mod_deps = backend_both_deps + os_deps
3119 backend_code = declare_dependency(
3120 compile_args: ['-DBUILDING_DLL'],
3121 include_directories: [postgres_inc],
3122 link_args: ldflags_be,
3124 sources: generated_headers + generated_backend_headers,
3125 dependencies: os_deps + backend_both_deps + backend_deps,
3128 # install these files only during test, not main install
3129 test_install_data = []
3130 test_install_libs = []
3132 # src/backend/meson.build defines backend_mod_code used for extension
3136 # Then through the main sources. That way contrib can have dependencies on
3137 # main sources. Note that this explicitly doesn't enter src/test, right now a
3138 # few regression tests depend on contrib files.
3145 subdir('src/interfaces/libpq/test')
3146 subdir('src/interfaces/ecpg/test')
3148 subdir('doc/src/sgml')
3150 generated_sources_ac += {'': ['GNUmakefile']}
3152 # After processing src/test, add test_install_libs to the testprep_targets
3154 testprep_targets += test_install_libs
3157 # If there are any files in the source directory that we also generate in the
3158 # build directory, they might get preferred over the newly generated files,
3159 # e.g. because of a #include "file", which always will search in the current
3161 message('checking for file conflicts between source and build directory')
3162 conflicting_files = []
3163 potentially_conflicting_files_t = []
3164 potentially_conflicting_files_t += generated_headers
3165 potentially_conflicting_files_t += generated_backend_headers
3166 potentially_conflicting_files_t += generated_backend_sources
3167 potentially_conflicting_files_t += generated_sources
3169 potentially_conflicting_files = []
3171 # convert all sources of potentially conflicting files into uniform shape
3172 foreach t : potentially_conflicting_files_t
3173 potentially_conflicting_files += t.full_path()
3175 foreach t1 : configure_files
3176 if meson.version().version_compare('>=0.59')
3177 t = fs.parent(t1) / fs.name(t1)
3179 t = '@0@'.format(t1)
3181 potentially_conflicting_files += meson.current_build_dir() / t
3183 foreach sub, fnames : generated_sources_ac
3184 sub = meson.build_root() / sub
3185 foreach fname : fnames
3186 potentially_conflicting_files += sub / fname
3190 # find and report conflicting files
3191 foreach build_path : potentially_conflicting_files
3192 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3193 # str.replace is in 0.56
3194 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3195 if fs.exists(src_path) or fs.is_symlink(src_path)
3196 conflicting_files += src_path
3199 # XXX: Perhaps we should generate a file that would clean these up? The list
3201 if conflicting_files.length() > 0
3202 errmsg_cleanup = '''
3203 Conflicting files in source directory:
3206 The conflicting files need to be removed, either by removing the files listed
3207 above, or by running configure and then make maintainer-clean.
3209 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3210 error(errmsg_nonclean_base.format(errmsg_cleanup))
3215 ###############################################################
3217 ###############################################################
3220 # We want to define additional install targets beyond what meson provides. For
3221 # that we need to define targets depending on nearly everything. We collected
3222 # the results of i18n.gettext() invocations into nls_targets, that also
3223 # includes maintainer targets though. Collect the ones we want as a dependency.
3225 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3226 # generation happens during install, so that's not a real issue.
3228 if libintl.found() and meson.version().version_compare('>=0.60')
3229 # use range() to avoid the flattening of the list that foreach() would do
3230 foreach off : range(0, nls_targets.length())
3231 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3232 # -pot target 3) maintainer -pot target
3233 nls_mo_targets += nls_targets[off][0]
3235 alias_target('nls', nls_mo_targets)
3250 # Meson's default install target is quite verbose. Provide one that is quiet.
3251 install_quiet = custom_target('install-quiet',
3252 output: 'install-quiet',
3253 build_always_stale: true,
3254 build_by_default: false,
3255 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3259 # Target to install files used for tests, which aren't installed by default
3260 install_test_files_args = [
3262 '--prefix', dir_prefix,
3263 '--install', contrib_data_dir, test_install_data,
3264 '--install', dir_lib_pkg, test_install_libs,
3266 run_target('install-test-files',
3267 command: [python] + install_test_files_args,
3268 depends: testprep_targets,
3273 ###############################################################
3275 ###############################################################
3277 # DESTDIR for the installation we'll run tests in
3278 test_install_destdir = meson.build_root() / 'tmp_install/'
3280 # DESTDIR + prefix appropriately munged
3281 if build_system != 'windows'
3282 # On unixoid systems this is trivial, we just prepend the destdir
3283 assert(dir_prefix.startswith('/')) # enforced by meson
3284 temp_install_bindir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_bin)
3285 temp_install_libdir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_lib)
3287 # drives, drive-relative paths, etc make this complicated on windows, call
3288 # into a copy of meson's logic for it
3291 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3292 test_install_destdir]
3293 temp_install_bindir = run_command(command, dir_prefix / dir_bin, check: true).stdout().strip()
3294 temp_install_libdir = run_command(command, dir_prefix / dir_lib, check: true).stdout().strip()
3297 meson_install_args = meson_args + ['install'] + {
3298 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3302 # setup tests should be run first,
3303 # so define priority for these
3304 setup_tests_priority = 100
3306 meson_bin, args: meson_install_args ,
3307 env: {'DESTDIR':test_install_destdir},
3308 priority: setup_tests_priority,
3313 test('install_test_files',
3315 args: install_test_files_args + ['--destdir', test_install_destdir],
3316 priority: setup_tests_priority,
3320 test_result_dir = meson.build_root() / 'testrun'
3323 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3324 # inevitable conflicts from running tests in parallel, hackishly assign
3325 # different ports for different tests.
3329 test_env = environment()
3331 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3332 test_env.set('PG_REGRESS', pg_regress.full_path())
3333 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3334 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3336 # Test suites that are not safe by default but can be run if selected
3337 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3338 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3339 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3341 # Add the temporary installation to the library search path on platforms where
3342 # that works (everything but windows, basically). On windows everything
3343 # library-like gets installed into bindir, solving that issue.
3344 if library_path_var != ''
3345 test_env.prepend(library_path_var, temp_install_libdir)
3349 # Create (and remove old) initdb template directory. Tests use that, where
3350 # possible, to make it cheaper to run tests.
3352 # Use python to remove the old cached initdb, as we cannot rely on a working
3353 # 'rm' binary on windows.
3354 test('initdb_cache',
3362 shutil.rmtree(sys.argv[1], ignore_errors=True)
3363 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3364 sys.exit(sp.returncode)
3366 test_initdb_template,
3367 temp_install_bindir / 'initdb',
3368 '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3371 priority: setup_tests_priority - 1,
3379 ###############################################################
3381 ###############################################################
3383 # When using a meson version understanding exclude_suites, define a
3384 # 'tmp_install' test setup (the default) that excludes tests running against a
3385 # pre-existing install and a 'running' setup that conflicts with creation of
3386 # the temporary installation and tap tests (which don't support running
3387 # against a running server).
3391 if meson.version().version_compare('>=0.57')
3394 runningcheck = false
3397 testwrap = files('src/tools/testwrap')
3399 foreach test_dir : tests
3402 '--basedir', meson.build_root(),
3403 '--srcdir', test_dir['sd'],
3406 foreach kind, v : test_dir
3407 if kind in ['sd', 'bd', 'name']
3413 if kind in ['regress', 'isolation', 'ecpg']
3414 if kind == 'regress'
3416 fallback_dbname = 'regression_@0@'
3417 elif kind == 'isolation'
3418 runner = pg_isolation_regress
3419 fallback_dbname = 'isolation_regression_@0@'
3421 runner = pg_regress_ecpg
3422 fallback_dbname = 'ecpg_regression_@0@'
3425 test_group = test_dir['name']
3426 test_group_running = test_dir['name'] + '-running'
3428 test_output = test_result_dir / test_group / kind
3429 test_output_running = test_result_dir / test_group_running/ kind
3431 # Unless specified by the test, choose a non-conflicting database name,
3432 # to avoid conflicts when running against existing server.
3433 dbname = t.get('dbname',
3434 fallback_dbname.format(test_dir['name']))
3436 test_command_base = [
3438 '--inputdir', t.get('inputdir', test_dir['sd']),
3439 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3441 '--dlpath', test_dir['bd'],
3442 '--max-concurrent-tests=20',
3444 ] + t.get('regress_args', [])
3447 if t.has_key('schedule')
3448 test_selection += ['--schedule', t['schedule'],]
3451 if kind == 'isolation'
3452 test_selection += t.get('specs', [])
3454 test_selection += t.get('sql', [])
3458 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3464 'depends': test_deps + t.get('deps', []),
3466 } + t.get('test_kwargs', {})
3468 test(test_group / kind,
3472 '--testgroup', test_group,
3476 '--outputdir', test_output,
3477 '--temp-instance', test_output / 'tmp_check',
3478 '--port', testport.to_string(),
3482 kwargs: test_kwargs,
3484 install_suites += test_group
3486 # some tests can't support running against running DB
3487 if runningcheck and t.get('runningcheck', true)
3488 test(test_group_running / kind,
3492 '--testgroup', test_group_running,
3496 '--outputdir', test_output_running,
3499 is_parallel: t.get('runningcheck-parallel', true),
3500 suite: test_group_running,
3501 kwargs: test_kwargs,
3503 running_suites += test_group_running
3508 testwrap_tap = testwrap_base
3509 if not tap_tests_enabled
3510 testwrap_tap += ['--skip', 'TAP tests not enabled']
3515 '-I', meson.source_root() / 'src/test/perl',
3516 '-I', test_dir['sd'],
3519 # Add temporary install, the build directory for non-installed binaries and
3520 # also test/ for non-installed test binaries built separately.
3522 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3524 foreach name, value : t.get('env', {})
3525 env.set(name, value)
3528 test_group = test_dir['name']
3531 'suite': test_group,
3533 'depends': test_deps + t.get('deps', []),
3535 } + t.get('test_kwargs', {})
3537 foreach onetap : t['tests']
3538 # Make tap test names prettier, remove t/ and .pl
3540 if onetap_p.startswith('t/')
3541 onetap_p = onetap.split('t/')[1]
3543 if onetap_p.endswith('.pl')
3544 onetap_p = fs.stem(onetap_p)
3547 test(test_dir['name'] / onetap_p,
3549 kwargs: test_kwargs,
3550 args: testwrap_tap + [
3551 '--testgroup', test_dir['name'],
3552 '--testname', onetap_p,
3554 test_dir['sd'] / onetap,
3558 install_suites += test_group
3560 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3563 endforeach # kinds of tests
3565 endforeach # directories with tests
3567 # repeat condition so meson realizes version dependency
3568 if meson.version().version_compare('>=0.57')
3569 add_test_setup('tmp_install',
3571 exclude_suites: running_suites)
3572 add_test_setup('running',
3573 exclude_suites: ['setup'] + install_suites)
3578 ###############################################################
3580 ###############################################################
3582 alias_target('backend', backend_targets)
3583 alias_target('bin', bin_targets + [libpq_st])
3584 alias_target('pl', pl_targets)
3585 alias_target('contrib', contrib_targets)
3586 alias_target('testprep', testprep_targets)
3588 alias_target('world', all_built, docs)
3589 alias_target('install-world', install_quiet, installdocs)
3593 perl, '-ne', 'next if /^#/; print',
3594 files('doc/src/sgml/targets-meson.txt'),
3600 ###############################################################
3601 # Distribution archive
3602 ###############################################################
3604 # Meson has its own distribution building command (meson dist), but we
3605 # are not using that at this point. The main problem is that, the way
3606 # they have implemented it, it is not deterministic. Also, we want it
3607 # to be equivalent to the "make" version for the time being. But the
3608 # target name "dist" in meson is reserved for that reason, so we call
3609 # the custom target "pgdist".
3611 git = find_program('git', required: false, native: true, disabler: true)
3612 bzip2 = find_program('bzip2', required: false, native: true)
3614 distdir = meson.project_name() + '-' + meson.project_version()
3616 pg_git_revision = get_option('PG_GIT_REVISION')
3618 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3619 # in case the environment has a different setting. Without this, a
3620 # tarball created on Windows might be different than on, and unusable
3621 # on, Unix machines.
3623 tar_gz = custom_target('tar.gz',
3624 build_always_stale: true,
3625 command: [git, '-C', '@SOURCE_ROOT@',
3626 '-c', 'core.autocrlf=false',
3628 '--format', 'tar.gz',
3630 '--prefix', distdir + '/',
3631 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3633 output: distdir + '.tar.gz',
3637 tar_bz2 = custom_target('tar.bz2',
3638 build_always_stale: true,
3639 command: [git, '-C', '@SOURCE_ROOT@',
3640 '-c', 'core.autocrlf=false',
3641 '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3643 '--format', 'tar.bz2',
3644 '--prefix', distdir + '/',
3645 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3647 output: distdir + '.tar.bz2',
3650 tar_bz2 = custom_target('tar.bz2',
3651 command: [perl, '-e', 'exit 1'],
3652 output: distdir + '.tar.bz2',
3656 alias_target('pgdist', [tar_gz, tar_bz2])
3658 # Make the standard "dist" command fail, to prevent accidental use.
3659 # But not if we are in a subproject, in case the parent project wants to
3660 # create a dist using the standard Meson command.
3661 if not meson.is_subproject()
3662 # We can only pass the identifier perl here when we depend on >= 0.55
3663 if meson.version().version_compare('>=0.55')
3664 meson.add_dist_script(perl, '-e', 'exit 1')
3670 ###############################################################
3671 # The End, The End, My Friend
3672 ###############################################################
3674 if meson.version().version_compare('>=0.57')
3678 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3679 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3680 'segment size': get_option('segsize_blocks') != 0 ?
3681 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3682 '@0@ GB'.format(get_option('segsize')),
3684 section: 'Data layout',
3689 'host system': '@0@ @1@'.format(host_system, host_cpu),
3690 'build system': '@0@ @1@'.format(build_machine.system(),
3691 build_machine.cpu_family()),
3698 'linker': '@0@'.format(cc.get_linker_id()),
3699 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3701 section: 'Compiler',
3706 'CPP FLAGS': ' '.join(cppflags),
3707 'C FLAGS, functional': ' '.join(cflags),
3708 'C FLAGS, warnings': ' '.join(cflags_warn),
3709 'C FLAGS, modules': ' '.join(cflags_mod),
3710 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3711 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3713 section: 'Compiler Flags',
3719 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3721 section: 'Compiler',
3726 'C++ FLAGS, functional': ' '.join(cxxflags),
3727 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3728 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3730 section: 'Compiler Flags',
3736 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3738 'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3740 section: 'Programs',
3746 'bsd_auth': bsd_auth,
3748 'docs_pdf': docs_pdf_dep,
3760 'plpython': python3_dep,
3762 'readline': readline,
3769 section: 'External libraries',