--- /dev/null
+# Entry point for building PostgreSQL with meson
+#
+# Good starting points for writing meson.build files are:
+# - https://mesonbuild.com/Syntax.html
+# - https://mesonbuild.com/Reference-manual.html
+
+project('postgresql',
+ ['c'],
+ version: '16devel',
+ license: 'PostgreSQL',
+
+ # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
+ # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
+ # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
+ meson_version: '>=0.54',
+ default_options: [
+ 'warning_level=1', #-Wall equivalent
+ 'buildtype=release',
+ ]
+)
+
+
+
+###############################################################
+# Basic prep
+###############################################################
+
+fs = import('fs')
+pkgconfig = import('pkgconfig')
+
+host_system = host_machine.system()
+host_cpu = host_machine.cpu_family()
+
+cc = meson.get_compiler('c')
+
+not_found_dep = dependency('', required: false)
+thread_dep = dependency('threads')
+
+
+
+###############################################################
+# Safety first
+###############################################################
+
+# It's very easy to get into confusing states when the source directory
+# contains an in-place build. E.g. the wrong pg_config.h will be used. So just
+# refuse to build in that case.
+#
+# There's a more elaborate check later, that checks for conflicts around all
+# generated files. But we can only do that much further down the line, so this
+# quick check seems worth it. Adhering to this advice should clean up the
+# conflict, but won't protect against somebody doing make distclean or just
+# removing pg_config.h
+errmsg_nonclean_base = '''
+****
+Non-clean source code directory detected.
+
+To build with meson the source tree may not have an in-place, ./configure
+style, build configured. You can have both meson and ./configure style builds
+for the same source tree by building out-of-source / VPATH with
+configure. Alternatively use a separate check out for meson based builds.
+
+@0@
+****'''
+if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
+ errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
+ error(errmsg_nonclean_base.format(errmsg_cleanup))
+endif
+
+
+
+###############################################################
+# Variables to be determined
+###############################################################
+
+postgres_inc_d = ['src/include']
+postgres_inc_d += get_option('extra_include_dirs')
+
+postgres_lib_d = get_option('extra_lib_dirs')
+
+cppflags = []
+
+cflags = []
+cxxflags = []
+cflags_warn = []
+cxxflags_warn = []
+cflags_mod = []
+cxxflags_mod = []
+
+ldflags = []
+ldflags_be = []
+ldflags_sl = []
+ldflags_mod = []
+
+test_c_args = []
+
+os_deps = []
+backend_both_deps = []
+backend_deps = []
+libpq_deps = []
+
+pg_sysroot = ''
+
+# source of data for pg_config.h etc
+cdata = configuration_data()
+
+
+
+###############################################################
+# Version and other metadata
+###############################################################
+
+pg_version = meson.project_version()
+
+if pg_version.endswith('devel')
+ pg_version_arr = [pg_version.split('devel')[0], '0']
+elif pg_version.contains('beta')
+ pg_version_arr = [pg_version.split('beta')[0], '0']
+elif pg_version.contains('rc')
+ pg_version_arr = [pg_version.split('rc')[0], '0']
+else
+ pg_version_arr = pg_version.split('.')
+endif
+
+pg_version_major = pg_version_arr[0].to_int()
+pg_version_minor = pg_version_arr[1].to_int()
+pg_version_num = (pg_version_major * 10000) + pg_version_minor
+
+pg_url = 'https://www.postgresql.org/'
+
+cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
+cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
+cdata.set_quoted('PACKAGE_URL', pg_url)
+cdata.set_quoted('PACKAGE_VERSION', pg_version)
+cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
+cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
+
+pg_version += get_option('extra_version')
+cdata.set_quoted('PG_VERSION', pg_version)
+cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by @2@-@3@'.format(
+ pg_version, build_machine.cpu_family(), cc.get_id(), cc.version()))
+cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
+cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
+cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
+cdata.set('PG_VERSION_NUM', pg_version_num)
+cdata.set_quoted('CONFIGURE_ARGS', '')
+
+
+
+###############################################################
+# Basic platform specific configuration
+###############################################################
+
+# meson's system names don't quite map to our "traditional" names. In some
+# places we need the "traditional" name, e.g., for mapping
+# src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
+# that purpose.
+portname = host_system
+
+exesuffix = '' # overridden below where necessary
+dlsuffix = '.so' # overridden below where necessary
+library_path_var = 'LD_LIBRARY_PATH'
+
+# Format of file to control exports from libraries, and how to pass them to
+# the compiler. For export_fmt @0@ is the path to the file export file.
+export_file_format = 'gnu'
+export_file_suffix = 'list'
+export_fmt = '-Wl,--version-script=@0@'
+
+# Flags to add when linking a postgres extension, @0@ is path to
+# the relevant object on the platform.
+mod_link_args_fmt = []
+
+memset_loop_limit = 1024
+
+# Choice of shared memory and semaphore implementation
+shmem_kind = 'sysv'
+sema_kind = 'sysv'
+
+# We implement support for some operating systems by pretending they're
+# another. Map here, before determining system properties below
+if host_system == 'dragonfly'
+ # apparently the most similar
+ host_system = 'netbsd'
+endif
+
+if host_system == 'aix'
+ library_path_var = 'LIBPATH'
+
+ export_file_format = 'aix'
+ export_fmt = '-Wl,-bE:@0@'
+ mod_link_args_fmt = ['-Wl,-bI:@0@']
+ mod_link_with_dir = 'libdir'
+ mod_link_with_name = '@0@.imp'
+
+ # M:SRE sets a flag indicating that an object is a shared library. Seems to
+ # work in some circumstances without, but required in others.
+ ldflags_sl += '-Wl,-bM:SRE'
+ ldflags_be += '-Wl,-brtllib'
+
+ # Native memset() is faster, tested on:
+ # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
+ # - AIX 5.3 ML3, gcc 4.0.1
+ memset_loop_limit = 0
+
+elif host_system == 'cygwin'
+ cppflags += '-D_GNU_SOURCE'
+
+elif host_system == 'darwin'
+ dlsuffix = '.dylib'
+ library_path_var = 'DYLD_LIBRARY_PATH'
+
+ export_file_format = 'darwin'
+ export_fmt = '-exported_symbols_list=@0@'
+
+ mod_link_args_fmt = ['-bundle_loader', '@0@']
+ mod_link_with_dir = 'bindir'
+ mod_link_with_name = '@0@'
+
+ sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
+ pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
+ message('darwin sysroot: @0@'.format(pg_sysroot))
+ cflags += ['-isysroot', pg_sysroot]
+ ldflags += ['-isysroot', pg_sysroot]
+
+elif host_system == 'freebsd'
+ sema_kind = 'unnamed_posix'
+
+elif host_system == 'linux'
+ sema_kind = 'unnamed_posix'
+ cppflags += '-D_GNU_SOURCE'
+
+elif host_system == 'netbsd'
+ # We must resolve all dynamic linking in the core server at program start.
+ # Otherwise the postmaster can self-deadlock due to signals interrupting
+ # resolution of calls, since NetBSD's linker takes a lock while doing that
+ # and some postmaster signal handlers do things that will also acquire that
+ # lock. As long as we need "-z now", might as well specify "-z relro" too.
+ # While there's not a hard reason to adopt these settings for our other
+ # executables, there's also little reason not to, so just add them to
+ # LDFLAGS.
+ ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
+
+elif host_system == 'openbsd'
+ # you're ok
+
+elif host_system == 'sunos'
+ portname = 'solaris'
+ export_fmt = '-Wl,-M@0@'
+ cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
+
+elif host_system == 'windows'
+ portname = 'win32'
+ exesuffix = '.exe'
+ dlsuffix = '.dll'
+ library_path_var = ''
+
+ export_file_format = 'win'
+ export_file_suffix = 'def'
+ if cc.get_id() == 'msvc'
+ export_fmt = '/DEF:@0@'
+ mod_link_with_name = '@0@.exe.lib'
+ else
+ export_fmt = '@0@'
+ mod_link_with_name = 'lib@0@.exe.a'
+ endif
+ mod_link_args_fmt = ['@0@']
+ mod_link_with_dir = 'libdir'
+
+ shmem_kind = 'win32'
+ sema_kind = 'win32'
+
+ cdata.set('WIN32_STACK_RLIMIT', 4194304)
+ if cc.get_id() == 'msvc'
+ ldflags += '/INCREMENTAL:NO'
+ ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+ # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
+ else
+ ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+ endif
+
+ os_deps += cc.find_library('ws2_32', required: true)
+ secur32_dep = cc.find_library('secur32', required: true)
+ backend_deps += secur32_dep
+ libpq_deps += secur32_dep
+
+ postgres_inc_d += 'src/include/port/win32'
+ if cc.get_id() == 'msvc'
+ postgres_inc_d += 'src/include/port/win32_msvc'
+ endif
+
+ windows = import('windows')
+
+else
+ # XXX: Should we add an option to override the host_system as an escape
+ # hatch?
+ error('unknown host system: @0@'.format(host_system))
+endif
+
+
+
+###############################################################
+# Program paths
+###############################################################
+
+# External programs
+perl = find_program(get_option('PERL'), required: true, native: true)
+python = find_program(get_option('PYTHON'), required: true, native: true)
+flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.31')
+bison = find_program(get_option('BISON'), native: true, version: '>= 1.875')
+sed = find_program(get_option('SED'), 'sed', native: true)
+prove = find_program(get_option('PROVE'), native: true)
+tar = find_program(get_option('TAR'), native: true)
+gzip = find_program(get_option('GZIP'), native: true)
+program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
+touch = find_program('touch', native: true)
+program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
+dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
+missing = find_program('config/missing', native: true)
+
+# used by PGXS
+install_sh = find_program('config/install-sh', native: true)
+
+bison_flags = []
+if bison.found()
+ bison_version_c = run_command(bison, '--version', check: true)
+ # bison version string helpfully is something like
+ # >>bison (GNU bison) 3.8.1<<
+ bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
+ if bison_version.version_compare('>=3.0')
+ bison_flags += ['-Wno-deprecated']
+ endif
+endif
+bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
+bison_kw = {
+ 'output': ['@BASENAME@.c', '@BASENAME@.h'],
+ 'command': bison_cmd,
+}
+
+flex_flags = []
+flex_wrapper = files('src/tools/pgflex')
+flex_cmd = [python, flex_wrapper,
+ '--builddir', '@BUILD_ROOT@',
+ '--srcdir', '@SOURCE_ROOT@',
+ '--privatedir', '@PRIVATE_DIR@',
+ '--flex', flex, '--perl', perl,
+ '-i', '@INPUT@', '-o', '@OUTPUT0@',
+]
+
+wget = find_program('wget', required: false, native: true)
+wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
+
+
+
+###############################################################
+# Path to meson (for tests etc)
+###############################################################
+
+# NB: this should really be part of meson, see
+# https://github.com/mesonbuild/meson/issues/8511
+meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
+
+if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
+ error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
+ meson_binpath_r.returncode(),
+ meson_binpath_r.stdout(),
+ meson_binpath_r.stderr()))
+endif
+
+meson_binpath_s = meson_binpath_r.stdout().split('\n')
+meson_binpath_len = meson_binpath_s.length()
+
+if meson_binpath_len < 1
+ error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
+endif
+
+i = 0
+meson_impl = ''
+meson_binpath = ''
+meson_args = []
+foreach e : meson_binpath_s
+ if i == 0
+ meson_impl = e
+ elif i == 1
+ meson_binpath = e
+ else
+ meson_args += e
+ endif
+ i += 1
+endforeach
+
+if meson_impl not in ['muon', 'meson']
+ error('unknown meson implementation "@0@"'.format(meson_impl))
+endif
+
+meson_bin = find_program(meson_binpath, native: true)
+
+
+
+###############################################################
+# Option Handling
+###############################################################
+
+cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
+
+cdata.set('BLCKSZ', get_option('blocksize').to_int() * 1024, description:
+'''Size of a disk block --- this also limits the size of a tuple. You can set
+ it bigger if you need bigger tuples (although TOAST should reduce the need
+ to have large tuples, since fields can be spread across multiple tuples).
+ BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+ currently 2^15 (32768). This is determined by the 15-bit widths of the
+ lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+ Changing BLCKSZ requires an initdb.''')
+
+cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
+cdata.set('RELSEG_SIZE', get_option('segsize') * 131072)
+cdata.set('DEF_PGPORT', get_option('pgport'))
+cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
+cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
+if get_option('system_tzdata') != ''
+ cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
+endif
+
+
+
+###############################################################
+# Directories
+###############################################################
+
+# These are set by the equivalent --xxxdir configure options. We
+# append "postgresql" to some of them, if the string does not already
+# contain "pgsql" or "postgres", in order to avoid directory clutter.
+
+pkg = 'postgresql'
+
+dir_prefix = get_option('prefix')
+
+dir_bin = get_option('bindir')
+
+dir_data = get_option('datadir')
+if not (dir_data.contains('pgsql') or dir_data.contains('postgres'))
+ dir_data = dir_data / pkg
+endif
+
+dir_sysconf = get_option('sysconfdir')
+if not (dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
+ dir_sysconf = dir_sysconf / pkg
+endif
+
+dir_lib = get_option('libdir')
+
+dir_lib_pkg = dir_lib
+if not (dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
+ dir_lib_pkg = dir_lib_pkg / pkg
+endif
+
+dir_pgxs = dir_lib_pkg / 'pgxs'
+
+dir_include = get_option('includedir')
+
+dir_include_pkg = dir_include
+dir_include_pkg_rel = ''
+if not (dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
+ dir_include_pkg = dir_include_pkg / pkg
+ dir_include_pkg_rel = pkg
+endif
+
+dir_man = get_option('mandir')
+
+# FIXME: These used to be separately configurable - worth adding?
+dir_doc = get_option('datadir') / 'doc' / 'postgresql'
+dir_doc_html = dir_doc
+
+dir_locale = get_option('localedir')
+
+
+# Derived values
+dir_bitcode = dir_lib_pkg / 'bitcode'
+dir_include_internal = dir_include_pkg / 'internal'
+dir_include_server = dir_include_pkg / 'server'
+dir_include_extension = dir_include_server / 'extension'
+dir_data_extension = dir_data / 'extension'
+
+
+
+###############################################################
+# Search paths, preparation for compiler tests
+#
+# NB: Arguments added later are not automatically used for subsequent
+# configuration-time checks (so they are more isolated). If they should be
+# used, they need to be added to test_c_args as well.
+###############################################################
+
+postgres_inc = [include_directories(postgres_inc_d)]
+test_lib_d = postgres_lib_d
+test_c_args = cppflags + cflags
+
+
+
+###############################################################
+# Library: bsd-auth
+###############################################################
+
+bsd_authopt = get_option('bsd_auth')
+bsd_auth = not_found_dep
+if cc.check_header('bsd_auth.h', required: bsd_authopt,
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('USE_BSD_AUTH', 1)
+ bsd_auth = declare_dependency()
+endif
+
+
+
+###############################################################
+# Library: bonjour
+#
+# For now don't search for DNSServiceRegister in a library - only Apple's
+# Bonjour implementation, which is always linked, works.
+###############################################################
+
+bonjouropt = get_option('bonjour')
+bonjour = dependency('', required : false)
+if cc.check_header('dns_sd.h', required: bonjouropt,
+ args: test_c_args, include_directories: postgres_inc) and \
+ cc.has_function('DNSServiceRegister',
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('USE_BONJOUR', 1)
+ bonjour = declare_dependency()
+endif
+
+
+
+###############################################################
+# Library: GSSAPI
+###############################################################
+
+gssapiopt = get_option('gssapi')
+krb_srvtab = ''
+have_gssapi = false
+if not gssapiopt.disabled()
+ gssapi = dependency('krb5-gssapi', required: gssapiopt)
+ have_gssapi = gssapi.found()
+
+ if not have_gssapi
+ elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
+ elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
+ cdata.set('HAVE_GSSAPI_H', 1)
+ else
+ have_gssapi = false
+ endif
+
+ if not have_gssapi
+ elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('ENABLE_GSS', 1)
+
+ krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
+ cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
+ elif gssapiopt.enabled()
+ error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
+ else
+ have_gssapi = false
+ endif
+endif
+if not have_gssapi
+ gssapi = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: ldap
+###############################################################
+
+ldapopt = get_option('ldap')
+if host_system == 'windows'
+ ldap = cc.find_library('wldap32', required: ldapopt)
+ ldap_r = ldap
+else
+ # macos framework dependency is buggy for ldap (one can argue whether it's
+ # Apple's or meson's fault), leading to an endless recursion with ldap.h
+ # including itself. See https://github.com/mesonbuild/meson/issues/10002
+ # Luckily we only need pkg-config support, so the workaround isn't
+ # complicated.
+ ldap = dependency('ldap', method: 'pkg-config', required: false)
+ ldap_r = ldap
+
+ # Before 2.5 openldap didn't have a pkg-config file, and it might not be
+ # installed
+ if not ldap.found()
+ ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
+ has_headers: 'ldap.h', header_include_directories: postgres_inc)
+
+ # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
+ # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
+ # library from a separate OpenLDAP installation). The most reliable
+ # way to check that is to check for a function introduced in 2.5.
+ if not ldap.found()
+ # don't have ldap, we shouldn't check for ldap_r
+ elif cc.has_function('ldap_verify_credentials',
+ dependencies: ldap, args: test_c_args)
+ ldap_r = ldap # ldap >= 2.5, no need for ldap_r
+ else
+
+ # Use ldap_r for FE if available, else assume ldap is thread-safe.
+ ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
+ has_headers: 'ldap.h', header_include_directories: postgres_inc)
+ if not ldap_r.found()
+ ldap_r = ldap
+ else
+ # On some platforms ldap_r fails to link without PTHREAD_LIBS.
+ ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
+ endif
+
+ # PostgreSQL sometimes loads libldap_r and plain libldap into the same
+ # process. Check for OpenLDAP versions known not to tolerate doing so;
+ # assume non-OpenLDAP implementations are safe. The dblink test suite
+ # exercises the hazardous interaction directly.
+ compat_test_code = '''
+#include <ldap.h>
+#if !defined(LDAP_VENDOR_VERSION) || \
+ (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
+ LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
+choke me
+#endif
+'''
+ if not cc.compiles(compat_test_code,
+ name: 'LDAP implementation compatible',
+ dependencies: ldap, args: test_c_args)
+ warning('''
+*** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
+*** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
+*** also uses LDAP will crash on exit.''')
+ endif
+ endif
+ endif
+
+ # XXX: this shouldn't be tested in the windows case, but should be tested in
+ # the dependency() success case
+ if ldap.found() and cc.has_function('ldap_initialize',
+ dependencies: ldap, args: test_c_args)
+ cdata.set('HAVE_LDAP_INITIALIZE', 1)
+ endif
+endif
+
+if ldap.found()
+ assert(ldap_r.found())
+ cdata.set('USE_LDAP', 1)
+else
+ assert(not ldap_r.found())
+endif
+
+
+
+###############################################################
+# Library: LLVM
+###############################################################
+
+llvmopt = get_option('llvm')
+if not llvmopt.disabled()
+ add_languages('cpp', required: true, native: false)
+ llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
+
+ if llvm.found()
+
+ cdata.set('USE_LLVM', 1)
+
+ cpp = meson.get_compiler('cpp')
+
+ llvm_binpath = llvm.get_variable(configtool: 'bindir')
+
+ ccache = find_program('ccache', native: true, required: false)
+ clang = find_program(llvm_binpath / 'clang', required: true)
+ endif
+else
+ llvm = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: icu
+###############################################################
+
+icuopt = get_option('icu')
+if not icuopt.disabled()
+ icu = dependency('icu-uc', required: icuopt.enabled())
+ icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
+
+ if icu.found()
+ cdata.set('USE_ICU', 1)
+ endif
+
+else
+ icu = not_found_dep
+ icu_i18n = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: libxml
+###############################################################
+
+libxmlopt = get_option('libxml')
+if not libxmlopt.disabled()
+ libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
+
+ if libxml.found()
+ cdata.set('USE_LIBXML', 1)
+ endif
+else
+ libxml = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: libxslt
+###############################################################
+
+libxsltopt = get_option('libxslt')
+if not libxsltopt.disabled()
+ libxslt = dependency('libxslt', required: libxsltopt)
+
+ if libxslt.found()
+ cdata.set('USE_LIBXSLT', 1)
+ endif
+else
+ libxslt = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: lz4
+###############################################################
+
+lz4opt = get_option('lz4')
+if not lz4opt.disabled()
+ lz4 = dependency('liblz4', required: lz4opt)
+
+ if lz4.found()
+ cdata.set('USE_LZ4', 1)
+ cdata.set('HAVE_LIBLZ4', 1)
+ endif
+
+else
+ lz4 = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Tcl (for pltcl)
+#
+# NB: tclConfig.sh is used in autoconf build for getting
+# TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
+# variables. For now we have not seen a need to copy
+# that behaviour to the meson build.
+###############################################################
+
+tclopt = get_option('pltcl')
+tcl_version = get_option('tcl_version')
+tcl_dep = not_found_dep
+if not tclopt.disabled()
+
+ # via pkg-config
+ tcl_dep = dependency(tcl_version, required: false)
+
+ if not tcl_dep.found()
+ tcl_dep = cc.find_library(tcl_version,
+ required: tclopt,
+ dirs: test_lib_d)
+ endif
+
+ if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
+ tcl_dep = not_found_dep
+ endif
+endif
+
+
+
+###############################################################
+# Library: pam
+###############################################################
+
+pamopt = get_option('pam')
+if not pamopt.disabled()
+ pam = dependency('pam', required: false)
+
+ if not pam.found()
+ pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
+ endif
+
+ if pam.found()
+ pam_header_found = false
+
+ # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
+ if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
+ pam_header_found = true
+ elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('HAVE_PAM_PAM_APPL_H', 1)
+ pam_header_found = true
+ endif
+
+ if pam_header_found
+ cdata.set('USE_PAM', 1)
+ else
+ pam = not_found_dep
+ endif
+ endif
+else
+ pam = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Perl (for plperl)
+###############################################################
+
+perlopt = get_option('plperl')
+perl_dep = not_found_dep
+if not perlopt.disabled()
+ perl_may_work = true
+
+ # First verify that perl has the necessary dependencies installed
+ perl_mods = run_command(
+ [perl,
+ '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
+ '-e', ''],
+ check: false)
+ if perl_mods.returncode() != 0
+ perl_may_work = false
+ perl_msg = 'perl installation does not have the required modules'
+ endif
+
+ # Then inquire perl about its configuration
+ if perl_may_work
+ perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
+ perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
+ archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
+ privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
+ useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
+
+ perl_inc_dir = '@0@/CORE'.format(archlibexp)
+
+ if useshrplib != 'true'
+ perl_may_work = false
+ perl_msg = 'need a shared perl'
+ endif
+ endif
+
+ if perl_may_work
+ # On most platforms, archlibexp is also where the Perl include files live ...
+ perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
+ # ... but on newer macOS versions, we must use -iwithsysroot to look
+ # under sysroot
+ if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
+ fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
+ perl_ccflags = ['-iwithsysroot', perl_inc_dir]
+ endif
+
+ # check compiler finds header
+ if not cc.has_header('perl.h', required: false,
+ args: test_c_args + perl_ccflags, include_directories: postgres_inc)
+ perl_may_work = false
+ perl_msg = 'missing perl.h'
+ endif
+ endif
+
+ if perl_may_work
+ perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
+
+ # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
+ foreach flag : perl_ccflags_r.split(' ')
+ if flag.startswith('-D') and \
+ (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
+ perl_ccflags += flag
+ endif
+ endforeach
+
+ if host_system == 'windows'
+ perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
+ endif
+
+ message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
+ message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
+
+ # We are after Embed's ldopts, but without the subset mentioned in
+ # Config's ccdlflags and ldflags. (Those are the choices of those who
+ # built the Perl installation, which are not necessarily appropriate
+ # for building PostgreSQL.)
+ ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
+ undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
+ undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
+
+ perl_ldopts = []
+ foreach ldopt : ldopts.split(' ')
+ if ldopt == '' or ldopt in undesired
+ continue
+ endif
+
+ perl_ldopts += ldopt.strip('"')
+ endforeach
+
+ message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
+ message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
+
+ perl_dep_int = declare_dependency(
+ compile_args: perl_ccflags,
+ link_args: perl_ldopts,
+ version: perlversion,
+ )
+
+ # While we're at it, check that we can link to libperl.
+ # On most platforms, if perl.h is there then libperl.so will be too, but
+ # at this writing Debian packages them separately.
+ perl_link_test = '''
+/* see plperl.h */
+#ifdef _MSC_VER
+#define __inline__ inline
+#endif
+#include <EXTERN.h>
+#include <perl.h>
+int main(void)
+{
+perl_alloc();
+}'''
+ if not cc.links(perl_link_test, name: 'libperl',
+ args: test_c_args + perl_ccflags + perl_ldopts,
+ include_directories: postgres_inc)
+ perl_may_work = false
+ perl_msg = 'missing libperl'
+ endif
+
+ endif # perl_may_work
+
+ if perl_may_work
+ perl_dep = perl_dep_int
+ else
+ if perlopt.enabled()
+ error('dependency plperl failed: @0@'.format(perl_msg))
+ else
+ message('disabling optional dependency plperl: @0@'.format(perl_msg))
+ endif
+ endif
+endif
+
+
+
+###############################################################
+# Library: Python (for plpython)
+###############################################################
+
+pyopt = get_option('plpython')
+if not pyopt.disabled()
+ pm = import('python')
+ python3_inst = pm.find_installation(required: pyopt.enabled())
+ python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
+ if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
+ python3_dep = not_found_dep
+ endif
+else
+ python3_dep = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Readline
+###############################################################
+
+if not get_option('readline').disabled()
+ libedit_preferred = get_option('libedit_preferred')
+ # Set the order of readline dependencies
+ check_readline_deps = libedit_preferred ? \
+ ['libedit', 'readline'] : ['readline', 'libedit']
+
+ foreach readline_dep : check_readline_deps
+ readline = dependency(readline_dep, required: false)
+ if not readline.found()
+ readline = cc.find_library(readline_dep,
+ required: get_option('readline').enabled(),
+ dirs: test_lib_d)
+ endif
+ if readline.found()
+ break
+ endif
+ endforeach
+
+ if readline.found()
+ cdata.set('HAVE_LIBREADLINE', 1)
+
+ editline_prefix = {
+ 'header_prefix': 'editline/',
+ 'flag_prefix': 'EDITLINE_',
+ }
+ readline_prefix = {
+ 'header_prefix': 'readline/',
+ 'flag_prefix': 'READLINE_',
+ }
+ default_prefix = {
+ 'header_prefix': '',
+ 'flag_prefix': '',
+ }
+
+ # Set the order of prefixes
+ prefixes = libedit_preferred ? \
+ [editline_prefix, default_prefix, readline_prefix] : \
+ [readline_prefix, default_prefix, editline_prefix]
+
+ at_least_one_header_found = false
+ foreach header : ['history', 'readline']
+ is_found = false
+ foreach prefix : prefixes
+ header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
+ # Check history.h and readline.h
+ if not is_found and cc.has_header(header_file,
+ args: test_c_args, include_directories: postgres_inc,
+ dependencies: [readline], required: false)
+ if header == 'readline'
+ readline_h = header_file
+ endif
+ cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
+ is_found = true
+ at_least_one_header_found = true
+ endif
+ endforeach
+ endforeach
+
+ if not at_least_one_header_found
+ error('''readline header not found
+If you have @0@ already installed, see see meson-log/meson-log.txt for details on the
+failure. It is possible the compiler isn't looking in the proper directory.
+Use -Dreadline=false to disable readline support.'''.format(readline_dep))
+ endif
+
+ check_funcs = [
+ 'append_history',
+ 'history_truncate_file',
+ 'rl_completion_matches',
+ 'rl_filename_completion_function',
+ 'rl_reset_screen_size',
+ 'rl_variable_bind',
+ ]
+
+ foreach func : check_funcs
+ found = cc.has_function(func, dependencies: [readline],
+ args: test_c_args, include_directories: postgres_inc)
+ cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
+ endforeach
+
+ check_vars = [
+ 'rl_completion_suppress_quote',
+ 'rl_filename_quote_characters',
+ 'rl_filename_quoting_function',
+ ]
+
+ foreach var : check_vars
+ cdata.set('HAVE_'+var.to_upper(),
+ cc.has_header_symbol(readline_h, var,
+ args: test_c_args, include_directories: postgres_inc,
+ prefix: '#include <stdio.h>',
+ dependencies: [readline]) ? 1 : false)
+ endforeach
+
+ # If found via cc.find_library() ensure headers are found when using the
+ # dependency. On meson < 0.57 one cannot do compiler checks using the
+ # dependency returned by declare_dependency(), so we can't do this above.
+ if readline.type_name() == 'library'
+ readline = declare_dependency(dependencies: readline,
+ include_directories: postgres_inc)
+ endif
+ endif
+
+ # XXX: Figure out whether to implement mingw warning equivalent
+else
+ readline = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: selinux
+###############################################################
+
+selinux = not_found_dep
+selinuxopt = get_option('selinux')
+if meson.version().version_compare('>=0.59')
+ selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
+endif
+selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
+cdata.set('HAVE_LIBSELINUX',
+ selinux.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: systemd
+###############################################################
+
+systemd = not_found_dep
+systemdopt = get_option('systemd')
+if meson.version().version_compare('>=0.59')
+ systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
+endif
+systemd = dependency('libsystemd', required: systemdopt)
+cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: SSL
+###############################################################
+
+if get_option('ssl') == 'openssl'
+
+ # Try to find openssl via pkg-config et al, if that doesn't work
+ # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
+ # the library names that we know about.
+
+ # via pkg-config et al
+ ssl = dependency('openssl', required: false)
+
+ # via library + headers
+ if not ssl.found()
+ ssl_lib = cc.find_library('ssl',
+ dirs: test_lib_d,
+ header_include_directories: postgres_inc,
+ has_headers: ['openssl/ssl.h', 'openssl/err.h'])
+ crypto_lib = cc.find_library('crypto',
+ dirs: test_lib_d,
+ header_include_directories: postgres_inc)
+ ssl_int = [ssl_lib, crypto_lib]
+
+ ssl = declare_dependency(dependencies: ssl_int,
+ include_directories: postgres_inc)
+ else
+ cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
+ cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
+
+ ssl_int = [ssl]
+ endif
+
+ check_funcs = [
+ ['CRYPTO_new_ex_data', {'required': true}],
+ ['SSL_new', {'required': true}],
+
+ # Function introduced in OpenSSL 1.0.2.
+ ['X509_get_signature_nid'],
+
+ # Functions introduced in OpenSSL 1.1.0. We used to check for
+ # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
+ # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
+ # doesn't have these OpenSSL 1.1.0 functions. So check for individual
+ # functions.
+ ['OPENSSL_init_ssl'],
+ ['BIO_get_data'],
+ ['BIO_meth_new'],
+ ['ASN1_STRING_get0_data'],
+ ['HMAC_CTX_new'],
+ ['HMAC_CTX_free'],
+
+ # OpenSSL versions before 1.1.0 required setting callback functions, for
+ # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
+ # function was removed.
+ ['CRYPTO_lock'],
+ ]
+
+ foreach c : check_funcs
+ func = c.get(0)
+ val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
+ required = c.get(1, {}).get('required', false)
+ if required and not val
+ error('openssl function @0@ is required'.format(func))
+ elif not required
+ cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
+ endif
+ endforeach
+
+ cdata.set('USE_OPENSSL', 1,
+ description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
+ cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
+ description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
+else
+ ssl = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: uuid
+###############################################################
+
+uuidopt = get_option('uuid')
+if uuidopt != 'none'
+ uuidname = uuidopt.to_upper()
+ if uuidopt == 'e2fs'
+ uuid = dependency('uuid', required: true)
+ uuidfunc = 'uuid_generate'
+ uuidheader = 'uuid/uuid.h'
+ elif uuidopt == 'bsd'
+ # libc should have uuid function
+ uuid = declare_dependency()
+ uuidfunc = 'uuid_to_string'
+ uuidheader = 'uuid.h'
+ elif uuidopt == 'ossp'
+ uuid = dependency('ossp-uuid', required: true)
+ uuidfunc = 'uuid_export'
+ uuidheader = 'ossp/uuid.h'
+ else
+ error('huh')
+ endif
+
+ if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
+ error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
+ endif
+ cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
+
+ cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
+ description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
+else
+ uuid = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: zlib
+###############################################################
+
+zlibopt = get_option('zlib')
+zlib = not_found_dep
+if not zlibopt.disabled()
+ zlib_t = dependency('zlib', required: zlibopt)
+
+ if zlib_t.type_name() == 'internal'
+ # if fallback was used, we don't need to test if headers are present (they
+ # aren't built yet, so we can't test)
+ zlib = zlib_t
+ elif not zlib_t.found()
+ warning('did not find zlib')
+ elif not cc.has_header('zlib.h',
+ args: test_c_args, include_directories: postgres_inc,
+ dependencies: [zlib_t], required: zlibopt.enabled())
+ warning('zlib header not found')
+ elif not cc.has_type('z_streamp',
+ dependencies: [zlib_t], prefix: '#include <zlib.h>',
+ args: test_c_args, include_directories: postgres_inc)
+ if zlibopt.enabled()
+ error('zlib version is too old')
+ else
+ warning('zlib version is too old')
+ endif
+ else
+ zlib = zlib_t
+ endif
+
+ if zlib.found()
+ cdata.set('HAVE_LIBZ', 1)
+ endif
+endif
+
+
+
+###############################################################
+# Library: tap test dependencies
+###############################################################
+
+# Check whether tap tests are enabled or not
+tap_tests_enabled = false
+tapopt = get_option('tap_tests')
+if not tapopt.disabled()
+ # Checking for perl modules for tap tests
+ perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
+ if perl_ipc_run_check.returncode() != 0
+ message(perl_ipc_run_check.stderr().strip())
+ if tapopt.enabled()
+ error('Additional Perl modules are required to run TAP tests.')
+ else
+ warning('Additional Perl modules are required to run TAP tests.')
+ endif
+ else
+ tap_tests_enabled = true
+ endif
+endif
+
+
+
+###############################################################
+# Library: zstd
+###############################################################
+
+zstdopt = get_option('zstd')
+if not zstdopt.disabled()
+ zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
+
+ if zstd.found()
+ cdata.set('USE_ZSTD', 1)
+ cdata.set('HAVE_LIBZSTD', 1)
+ endif
+
+else
+ zstd = not_found_dep
+endif
+
+
+
+###############################################################
+# Compiler tests
+###############################################################
+
+# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
+# unnecessarily, because we optionally rely on newer features.
+c99_test = '''
+#include <stdbool.h>
+#include <complex.h>
+#include <tgmath.h>
+#include <inttypes.h>
+
+struct named_init_test {
+ int a;
+ int b;
+};
+
+extern void structfunc(struct named_init_test);
+
+int main(int argc, char **argv)
+{
+ struct named_init_test nit = {
+ .a = 3,
+ .b = 5,
+ };
+
+ for (int loop_var = 0; loop_var < 3; loop_var++)
+ {
+ nit.a += nit.b;
+ }
+
+ structfunc((struct named_init_test){1, 0});
+
+ return nit.a != 0;
+}
+'''
+
+if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
+ if cc.compiles(c99_test, name: 'c99 with -std=c99',
+ args: test_c_args + ['-std=c99'])
+ test_c_args += '-std=c99'
+ cflags += '-std=c99'
+ else
+ error('C compiler does not support C99')
+ endif
+endif
+
+sizeof_long = cc.sizeof('long', args: test_c_args)
+cdata.set('SIZEOF_LONG', sizeof_long)
+if sizeof_long == 8
+ cdata.set('HAVE_LONG_INT_64', 1)
+ cdata.set('PG_INT64_TYPE', 'long int')
+ cdata.set_quoted('INT64_MODIFIER', 'l')
+elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
+ cdata.set('HAVE_LONG_LONG_INT_64', 1)
+ cdata.set('PG_INT64_TYPE', 'long long int')
+ cdata.set_quoted('INT64_MODIFIER', 'll')
+else
+ error('do not know how to get a 64bit int')
+endif
+
+if host_machine.endian() == 'big'
+ cdata.set('WORDS_BIGENDIAN', 1)
+endif
+
+alignof_types = ['short', 'int', 'long', 'double']
+maxalign = 0
+foreach t : alignof_types
+ align = cc.alignment(t, args: test_c_args)
+ if maxalign < align
+ maxalign = align
+ endif
+ cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
+endforeach
+cdata.set('MAXIMUM_ALIGNOF', maxalign)
+
+cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
+cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
+
+
+# Check if __int128 is a working 128 bit integer type, and if so
+# define PG_INT128_TYPE to that typename.
+#
+# This currently only detects a GCC/clang extension, but support for other
+# environments may be added in the future.
+#
+# For the moment we only test for support for 128bit math; support for
+# 128bit literals and snprintf is not required.
+if cc.links('''
+ /*
+ * We don't actually run this test, just link it to verify that any support
+ * functions needed for __int128 are present.
+ *
+ * These are globals to discourage the compiler from folding all the
+ * arithmetic tests down to compile-time constants. We do not have
+ * convenient support for 128bit literals at this point...
+ */
+ __int128 a = 48828125;
+ __int128 b = 97656250;
+
+ int main(void)
+ {
+ __int128 c,d;
+ a = (a << 12) + 1; /* 200000000001 */
+ b = (b << 12) + 5; /* 400000000005 */
+ /* try the most relevant arithmetic ops */
+ c = a * b;
+ d = (c + b) / b;
+ /* must use the results, else compiler may optimize arithmetic away */
+ return d != a+1;
+ }''',
+ name: '__int128',
+ args: test_c_args)
+
+ buggy_int128 = false
+
+ # Use of non-default alignment with __int128 tickles bugs in some compilers.
+ # If not cross-compiling, we can test for bugs and disable use of __int128
+ # with buggy compilers. If cross-compiling, hope for the best.
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
+ if not meson.is_cross_build()
+ r = cc.run('''
+ /* This must match the corresponding code in c.h: */
+ #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
+ #define pg_attribute_aligned(a) __attribute__((aligned(a)))
+ #endif
+ typedef __int128 int128a
+ #if defined(pg_attribute_aligned)
+ pg_attribute_aligned(8)
+ #endif
+ ;
+
+ int128a holder;
+ void pass_by_val(void *buffer, int128a par) { holder = par; }
+
+ int main(void)
+ {
+ long int i64 = 97656225L << 12;
+ int128a q;
+ pass_by_val(main, (int128a) i64);
+ q = (int128a) i64;
+ return q != holder;
+ }''',
+ name: '__int128 alignment bug',
+ args: test_c_args)
+ assert(r.compiled())
+ if r.returncode() != 0
+ buggy_int128 = true
+ message('__int128 support present but buggy and thus disabled')
+ endif
+ endif
+
+ if not buggy_int128
+ cdata.set('PG_INT128_TYPE', '__int128')
+ cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
+ alignment('__int128', args: test_c_args))
+ endif
+endif
+
+
+# Check if the C compiler knows computed gotos (gcc extension, also
+# available in at least clang). If so, define HAVE_COMPUTED_GOTO.
+#
+# Checking whether computed gotos are supported syntax-wise ought to
+# be enough, as the syntax is otherwise illegal.
+if cc.compiles('''
+ static inline int foo(void)
+ {
+ void *labeladdrs[] = {&&my_label};
+ goto *labeladdrs[0];
+ my_label:
+ return 1;
+ }''',
+ args: test_c_args)
+ cdata.set('HAVE_COMPUTED_GOTO', 1)
+endif
+
+
+# Check if the C compiler understands _Static_assert(),
+# and define HAVE__STATIC_ASSERT if so.
+#
+# We actually check the syntax ({ _Static_assert(...) }), because we need
+# gcc-style compound expressions to be able to wrap the thing into macros.
+if cc.compiles('''
+ int main(int arg, char **argv)
+ {
+ ({ _Static_assert(1, "foo"); });
+ }
+ ''',
+ args: test_c_args)
+ cdata.set('HAVE__STATIC_ASSERT', 1)
+endif
+
+
+# We use <stdbool.h> if we have it and it declares type bool as having
+# size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
+if cc.has_type('_Bool', args: test_c_args) \
+ and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
+ and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
+ cdata.set('HAVE__BOOL', 1)
+ cdata.set('PG_USE_STDBOOL', 1)
+endif
+
+
+# Need to check a call with %m because netbsd supports gnu_printf but emits a
+# warning for each use of %m.
+printf_attributes = ['gnu_printf', '__syslog__', 'printf']
+testsrc = '''
+extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
+static void call_log(void)
+{
+ emit_log(0, "error: %s: %m", "foo");
+}
+'''
+attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
+foreach a : printf_attributes
+ if cc.compiles(testsrc.format(a),
+ args: test_c_args + attrib_error_args, name: 'format ' + a)
+ cdata.set('PG_PRINTF_ATTRIBUTE', a)
+ break
+ endif
+endforeach
+
+
+if cc.has_function_attribute('visibility:default') and \
+ cc.has_function_attribute('visibility:hidden')
+ cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
+
+ # Only newer versions of meson know not to apply gnu_symbol_visibility =
+ # inlineshidden to C code as well... Any either way, we want to put these
+ # flags into exported files (pgxs, .pc files).
+ cflags_mod += '-fvisibility=hidden'
+ cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
+ ldflags_mod += '-fvisibility=hidden'
+endif
+
+
+# Check if various builtins exist. Some builtins are tested separately,
+# because we want to test something more complicated than the generic case.
+builtins = [
+ 'bswap16',
+ 'bswap32',
+ 'bswap64',
+ 'clz',
+ 'ctz',
+ 'constant_p',
+ 'frame_address',
+ 'popcount',
+ 'unreachable',
+]
+
+foreach builtin : builtins
+ fname = '__builtin_@0@'.format(builtin)
+ if cc.has_function(fname, args: test_c_args)
+ cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
+ endif
+endforeach
+
+
+# Check if the C compiler understands __builtin_types_compatible_p,
+# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
+#
+# We check usage with __typeof__, though it's unlikely any compiler would
+# have the former and not the latter.
+if cc.compiles('''
+ static int x;
+ static int y[__builtin_types_compatible_p(__typeof__(x), int)];
+ ''',
+ name: '__builtin_types_compatible_p',
+ args: test_c_args)
+ cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
+endif
+
+
+# Check if the C compiler understands __builtin_$op_overflow(),
+# and define HAVE__BUILTIN_OP_OVERFLOW if so.
+#
+# Check for the most complicated case, 64 bit multiplication, as a
+# proxy for all of the operations. To detect the case where the compiler
+# knows the function but library support is missing, we must link not just
+# compile, and store the results in global variables so the compiler doesn't
+# optimize away the call.
+if cc.links('''
+ INT64 a = 1;
+ INT64 b = 1;
+ INT64 result;
+
+ int main(void)
+ {
+ return __builtin_mul_overflow(a, b, &result);
+ }''',
+ name: '__builtin_mul_overflow',
+ args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
+ )
+ cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
+endif
+
+
+# XXX: The configure.ac check for __cpuid() is broken, we don't copy that
+# here. To prevent problems due to two detection methods working, stop
+# checking after one.
+if cc.links('''
+ #include <cpuid.h>
+ int main(int arg, char **argv)
+ {
+ unsigned int exx[4] = {0, 0, 0, 0};
+ __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+ }
+ ''', name: '__get_cpuid',
+ args: test_c_args)
+ cdata.set('HAVE__GET_CPUID', 1)
+elif cc.links('''
+ #include <intrin.h>
+ int main(int arg, char **argv)
+ {
+ unsigned int exx[4] = {0, 0, 0, 0};
+ __cpuid(exx, 1);
+ }
+ ''', name: '__cpuid',
+ args: test_c_args)
+ cdata.set('HAVE__CPUID', 1)
+endif
+
+
+# Defend against clang being used on x86-32 without SSE2 enabled. As current
+# versions of clang do not understand -fexcess-precision=standard, the use of
+# x87 floating point operations leads to problems like isinf possibly returning
+# false for a value that is infinite when converted from the 80bit register to
+# the 8byte memory representation.
+#
+# Only perform the test if the compiler doesn't understand
+# -fexcess-precision=standard, that way a potentially fixed compiler will work
+# automatically.
+if '-fexcess-precision=standard' not in cflags
+ if not cc.compiles('''
+#if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
+choke me
+#endif''',
+ name: '', args: test_c_args)
+ error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
+ endif
+endif
+
+
+
+###############################################################
+# Compiler flags
+###############################################################
+
+common_functional_flags = [
+ # Disable strict-aliasing rules; needed for gcc 3.3+
+ '-fno-strict-aliasing',
+ # Disable optimizations that assume no overflow; needed for gcc 4.3+
+ '-fwrapv',
+ '-fexcess-precision=standard',
+]
+
+cflags += cc.get_supported_arguments(common_functional_flags)
+if llvm.found()
+ cxxflags += cpp.get_supported_arguments(common_functional_flags)
+endif
+
+vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
+unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
+
+common_warning_flags = [
+ '-Wmissing-prototypes',
+ '-Wpointer-arith',
+ # Really don't want VLAs to be used in our dialect of C
+ '-Werror=vla',
+ # On macOS, complain about usage of symbols newer than the deployment target
+ '-Werror=unguarded-availability-new',
+ '-Wendif-labels',
+ '-Wmissing-format-attribute',
+ '-Wimplicit-fallthrough=3',
+ '-Wcast-function-type',
+ # This was included in -Wall/-Wformat in older GCC versions
+ '-Wformat-security',
+]
+
+cflags_warn += cc.get_supported_arguments(common_warning_flags)
+if llvm.found()
+ cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
+endif
+
+# A few places with imported code get a pass on -Wdeclaration-after-statement, remember
+# the result for them
+if cc.has_argument('-Wdeclaration-after-statement')
+ cflags_warn += '-Wdeclaration-after-statement'
+ using_declaration_after_statement_warning = true
+else
+ using_declaration_after_statement_warning = false
+endif
+
+
+# The following tests want to suppress various unhelpful warnings by adding
+# -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
+# switches, so we have to test for the positive form and if that works,
+# add the negative form.
+
+negative_warning_flags = [
+ # Suppress clang's unhelpful unused-command-line-argument warnings.
+ 'unused-command-line-argument',
+
+ # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
+ # of warnings when building plperl because of usages in the Perl headers.
+ 'compound-token-split-by-macro',
+
+ # Similarly disable useless truncation warnings from gcc 8+
+ 'format-truncation',
+ 'stringop-truncation',
+
+ # To make warning_level=2 / -Wextra work, we'd need at least the following
+ # 'clobbered',
+ # 'missing-field-initializers',
+ # 'sign-compare',
+ # 'unused-parameter',
+]
+
+foreach w : negative_warning_flags
+ if cc.has_argument('-W' + w)
+ cflags_warn += '-Wno-' + w
+ endif
+ if llvm.found() and cpp.has_argument('-W' + w)
+ cxxflags_warn += '-Wno-' + w
+ endif
+endforeach
+
+
+# From Project.pm
+if cc.get_id() == 'msvc'
+ cflags_warn += [
+ '/wd4018', # signed/unsigned mismatch
+ '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
+ '/wd4273', # inconsistent DLL linkage
+ '/wd4101', # unreferenced local variable
+ '/wd4102', # unreferenced label
+ '/wd4090', # different 'modifier' qualifiers
+ '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
+ ]
+
+ cppflags += [
+ '/DWIN32',
+ '/DWINDOWS',
+ '/D__WINDOWS__',
+ '/D__WIN32__',
+ '/D_CRT_SECURE_NO_DEPRECATE',
+ '/D_CRT_NONSTDC_NO_DEPRECATE',
+ ]
+
+ # We never need export libraries. As link.exe reports their creation, they
+ # are unnecessarily noisy. Similarly, we don't need import library for
+ # modules, we only import them dynamically, and they're also noisy.
+ ldflags += '/NOEXP'
+ ldflags_mod += '/NOIMPLIB'
+endif
+
+
+
+###############################################################
+# Atomics
+###############################################################
+
+if not get_option('spinlocks')
+ warning('Not using spinlocks will cause poor performance')
+else
+ cdata.set('HAVE_SPINLOCKS', 1)
+endif
+
+if not get_option('atomics')
+ warning('Not using atomics will cause poor performance')
+else
+ # XXX: perhaps we should require some atomics support in this case these
+ # days?
+ cdata.set('HAVE_ATOMICS', 1)
+
+ atomic_checks = [
+ {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
+ 'desc': '__sync_lock_test_and_set(char)',
+ 'test': '''
+char lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+ {'name': 'HAVE_GCC__SYNC_INT32_TAS',
+ 'desc': '__sync_lock_test_and_set(int32)',
+ 'test': '''
+int lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+ {'name': 'HAVE_GCC__SYNC_INT32_CAS',
+ 'desc': '__sync_val_compare_and_swap(int32)',
+ 'test': '''
+int val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+ {'name': 'HAVE_GCC__SYNC_INT64_CAS',
+ 'desc': '__sync_val_compare_and_swap(int64)',
+ 'test': '''
+INT64 val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+ {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
+ 'desc': ' __atomic_compare_exchange_n(int32)',
+ 'test': '''
+int val = 0;
+int expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
+
+ {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
+ 'desc': ' __atomic_compare_exchange_n(int64)',
+ 'test': '''
+INT64 val = 0;
+INT64 expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
+ ]
+
+ foreach check : atomic_checks
+ test = '''
+int main(void)
+{
+@0@
+}'''.format(check['test'])
+
+ cdata.set(check['name'],
+ cc.links(test,
+ name: check['desc'],
+ args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
+ )
+ endforeach
+
+endif
+
+
+
+###############################################################
+# Select CRC-32C implementation.
+#
+# If we are targeting a processor that has Intel SSE 4.2 instructions, we can
+# use the special CRC instructions for calculating CRC-32C. If we're not
+# targeting such a processor, but we can nevertheless produce code that uses
+# the SSE intrinsics, perhaps with some extra CFLAGS, compile both
+# implementations and select which one to use at runtime, depending on whether
+# SSE 4.2 is supported by the processor we're running on.
+#
+# Similarly, if we are targeting an ARM processor that has the CRC
+# instructions that are part of the ARMv8 CRC Extension, use them. And if
+# we're not targeting such a processor, but can nevertheless produce code that
+# uses the CRC instructions, compile both, and select at runtime.
+###############################################################
+
+have_optimized_crc = false
+cflags_crc = []
+if host_cpu == 'x86' or host_cpu == 'x86_64'
+
+ if cc.get_id() == 'msvc'
+ cdata.set('USE_SSE42_CRC32C', false)
+ cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
+ have_optimized_crc = true
+ else
+
+ prog = '''
+#include <nmmintrin.h>
+
+int main(void)
+{
+ unsigned int crc = 0;
+ crc = _mm_crc32_u8(crc, 0);
+ crc = _mm_crc32_u32(crc, 0);
+ /* return computed value, to prevent the above being optimized away */
+ return crc == 0;
+}
+'''
+
+ if cc.links(prog, name: