1 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
3 # Entry point for building PostgreSQL with meson
5 # Good starting points for writing meson.build files are:
6 # - https://mesonbuild.com/Syntax.html
7 # - https://mesonbuild.com/Reference-manual.html
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 maintainer-clean 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 # meson's system names don't quite map to our "traditional" names. In some
163 # places we need the "traditional" name, e.g., for mapping
164 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
166 portname = host_system
168 exesuffix = '' # overridden below where necessary
169 dlsuffix = '.so' # overridden below where necessary
170 library_path_var = 'LD_LIBRARY_PATH'
172 # Format of file to control exports from libraries, and how to pass them to
173 # the compiler. For export_fmt @0@ is the path to the file export file.
174 export_file_format = 'gnu'
175 export_file_suffix = 'list'
176 export_fmt = '-Wl,--version-script=@0@'
178 # Flags to add when linking a postgres extension, @0@ is path to
179 # the relevant object on the platform.
180 mod_link_args_fmt = []
182 memset_loop_limit = 1024
184 # Choice of shared memory and semaphore implementation
188 # We implement support for some operating systems by pretending they're
189 # another. Map here, before determining system properties below
190 if host_system == 'dragonfly'
191 # apparently the most similar
192 host_system = 'netbsd'
195 if host_system == 'aix'
196 library_path_var = 'LIBPATH'
198 export_file_format = 'aix'
199 export_fmt = '-Wl,-bE:@0@'
200 mod_link_args_fmt = ['-Wl,-bI:@0@']
201 mod_link_with_dir = 'libdir'
202 mod_link_with_name = '@0@.imp'
204 # M:SRE sets a flag indicating that an object is a shared library. Seems to
205 # work in some circumstances without, but required in others.
206 ldflags_sl += '-Wl,-bM:SRE'
207 ldflags_be += '-Wl,-brtllib'
209 # Native memset() is faster, tested on:
210 # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
211 # - AIX 5.3 ML3, gcc 4.0.1
212 memset_loop_limit = 0
214 elif host_system == 'cygwin'
215 sema_kind = 'unnamed_posix'
216 cppflags += '-D_GNU_SOURCE'
218 mod_link_args_fmt = ['@0@']
219 mod_link_with_name = 'lib@0@.exe.a'
220 mod_link_with_dir = 'libdir'
222 elif host_system == 'darwin'
224 library_path_var = 'DYLD_LIBRARY_PATH'
226 export_file_format = 'darwin'
227 export_fmt = '-Wl,-exported_symbols_list,@0@'
229 mod_link_args_fmt = ['-bundle_loader', '@0@']
230 mod_link_with_dir = 'bindir'
231 mod_link_with_name = '@0@'
233 sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
234 pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
235 message('darwin sysroot: @0@'.format(pg_sysroot))
237 cflags += ['-isysroot', pg_sysroot]
238 ldflags += ['-isysroot', pg_sysroot]
240 # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
241 # don't want because a) it's different from what we do for autoconf, b) it
242 # causes warnings starting in macOS Ventura
243 ldflags_mod += ['-Wl,-undefined,error']
245 elif host_system == 'freebsd'
246 sema_kind = 'unnamed_posix'
248 elif host_system == 'linux'
249 sema_kind = 'unnamed_posix'
250 cppflags += '-D_GNU_SOURCE'
252 elif host_system == 'netbsd'
253 # We must resolve all dynamic linking in the core server at program start.
254 # Otherwise the postmaster can self-deadlock due to signals interrupting
255 # resolution of calls, since NetBSD's linker takes a lock while doing that
256 # and some postmaster signal handlers do things that will also acquire that
257 # lock. As long as we need "-z now", might as well specify "-z relro" too.
258 # While there's not a hard reason to adopt these settings for our other
259 # executables, there's also little reason not to, so just add them to
261 ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
263 elif host_system == 'openbsd'
266 elif host_system == 'sunos'
268 export_fmt = '-Wl,-M@0@'
269 cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
271 elif host_system == 'windows'
275 library_path_var = ''
277 export_file_format = 'win'
278 export_file_suffix = 'def'
279 if cc.get_id() == 'msvc'
280 export_fmt = '/DEF:@0@'
281 mod_link_with_name = '@0@.exe.lib'
284 mod_link_with_name = 'lib@0@.exe.a'
286 mod_link_args_fmt = ['@0@']
287 mod_link_with_dir = 'libdir'
292 cdata.set('WIN32_STACK_RLIMIT', 4194304)
293 if cc.get_id() == 'msvc'
294 ldflags += '/INCREMENTAL:NO'
295 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
296 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
298 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
299 # Need to allow multiple definitions, we e.g. want to override getopt.
300 ldflags += '-Wl,--allow-multiple-definition'
301 # Ensure we get MSVC-like linking behavior.
302 ldflags += '-Wl,--disable-auto-import'
305 os_deps += cc.find_library('ws2_32', required: true)
306 secur32_dep = cc.find_library('secur32', required: true)
307 backend_deps += secur32_dep
308 libpq_deps += secur32_dep
310 postgres_inc_d += 'src/include/port/win32'
311 if cc.get_id() == 'msvc'
312 postgres_inc_d += 'src/include/port/win32_msvc'
315 windows = import('windows')
318 # XXX: Should we add an option to override the host_system as an escape
320 error('unknown host system: @0@'.format(host_system))
325 ###############################################################
327 ###############################################################
330 perl = find_program(get_option('PERL'), required: true, native: true)
331 python = find_program(get_option('PYTHON'), required: true, native: true)
332 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
333 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
334 sed = find_program(get_option('SED'), 'sed', native: true)
335 prove = find_program(get_option('PROVE'), native: true, required: false)
336 tar = find_program(get_option('TAR'), native: true)
337 gzip = find_program(get_option('GZIP'), native: true)
338 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
339 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
340 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
341 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
342 missing = find_program('config/missing', native: true)
343 cp = find_program('cp', required: false, native: true)
344 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
345 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
349 bison_version_c = run_command(bison, '--version', check: true)
350 # bison version string helpfully is something like
351 # >>bison (GNU bison) 3.8.1<<
352 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
353 if bison_version.version_compare('>=3.0')
354 bison_flags += ['-Wno-deprecated']
357 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
359 'output': ['@BASENAME@.c', '@BASENAME@.h'],
360 'command': bison_cmd,
364 flex_wrapper = files('src/tools/pgflex')
365 flex_cmd = [python, flex_wrapper,
366 '--builddir', '@BUILD_ROOT@',
367 '--srcdir', '@SOURCE_ROOT@',
368 '--privatedir', '@PRIVATE_DIR@',
369 '--flex', flex, '--perl', perl,
370 '-i', '@INPUT@', '-o', '@OUTPUT0@',
373 wget = find_program('wget', required: false, native: true)
374 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
376 install_files = files('src/tools/install_files')
380 ###############################################################
381 # Path to meson (for tests etc)
382 ###############################################################
384 # NB: this should really be part of meson, see
385 # https://github.com/mesonbuild/meson/issues/8511
386 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
388 if meson_binpath_r.stdout() == ''
389 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
390 meson_binpath_r.returncode(),
391 meson_binpath_r.stdout(),
392 meson_binpath_r.stderr()))
395 meson_binpath_s = meson_binpath_r.stdout().split('\n')
396 meson_binpath_len = meson_binpath_s.length()
398 if meson_binpath_len < 1
399 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
406 foreach e : meson_binpath_s
417 if meson_impl not in ['muon', 'meson']
418 error('unknown meson implementation "@0@"'.format(meson_impl))
421 meson_bin = find_program(meson_binpath, native: true)
425 ###############################################################
427 ###############################################################
429 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
431 blocksize = get_option('blocksize').to_int() * 1024
433 if get_option('segsize_blocks') != 0
434 if get_option('segsize') != 1
435 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
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' / 'postgresql'
511 dir_doc_html = dir_doc / 'html'
513 dir_locale = get_option('localedir')
517 dir_bitcode = dir_lib_pkg / 'bitcode'
518 dir_include_internal = dir_include_pkg / 'internal'
519 dir_include_server = dir_include_pkg / 'server'
520 dir_include_extension = dir_include_server / 'extension'
521 dir_data_extension = dir_data / 'extension'
525 ###############################################################
526 # Search paths, preparation for compiler tests
528 # NB: Arguments added later are not automatically used for subsequent
529 # configuration-time checks (so they are more isolated). If they should be
530 # used, they need to be added to test_c_args as well.
531 ###############################################################
533 postgres_inc = [include_directories(postgres_inc_d)]
534 test_lib_d = postgres_lib_d
535 test_c_args = cppflags + cflags
539 ###############################################################
541 ###############################################################
543 bsd_authopt = get_option('bsd_auth')
544 bsd_auth = not_found_dep
545 if cc.check_header('bsd_auth.h', required: bsd_authopt,
546 args: test_c_args, include_directories: postgres_inc)
547 cdata.set('USE_BSD_AUTH', 1)
548 bsd_auth = declare_dependency()
553 ###############################################################
556 # For now don't search for DNSServiceRegister in a library - only Apple's
557 # Bonjour implementation, which is always linked, works.
558 ###############################################################
560 bonjouropt = get_option('bonjour')
561 bonjour = not_found_dep
562 if cc.check_header('dns_sd.h', required: bonjouropt,
563 args: test_c_args, include_directories: postgres_inc) and \
564 cc.has_function('DNSServiceRegister',
565 args: test_c_args, include_directories: postgres_inc)
566 cdata.set('USE_BONJOUR', 1)
567 bonjour = declare_dependency()
572 ###############################################################
573 # Option: docs in HTML and man page format
574 ###############################################################
576 docs_opt = get_option('docs')
577 docs_dep = not_found_dep
578 if not docs_opt.disabled()
579 if xmllint_bin.found() and xsltproc_bin.found()
580 docs_dep = declare_dependency()
581 elif docs_opt.enabled()
582 error('missing required tools for docs in HTML / man page format')
588 ###############################################################
589 # Option: docs in PDF format
590 ###############################################################
592 docs_pdf_opt = get_option('docs_pdf')
593 docs_pdf_dep = not_found_dep
594 if not docs_pdf_opt.disabled()
595 fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
596 if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
597 docs_pdf_dep = declare_dependency()
598 elif docs_pdf_opt.enabled()
599 error('missing required tools for docs in PDF format')
605 ###############################################################
607 ###############################################################
609 gssapiopt = get_option('gssapi')
612 if not gssapiopt.disabled()
613 gssapi = dependency('krb5-gssapi', required: gssapiopt)
614 have_gssapi = gssapi.found()
617 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
618 args: test_c_args, include_directories: postgres_inc)
619 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
620 elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
621 cdata.set('HAVE_GSSAPI_H', 1)
627 elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi, required: false,
628 args: test_c_args, include_directories: postgres_inc)
629 cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
630 elif cc.check_header('gssapi_ext.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
631 cdata.set('HAVE_GSSAPI_EXT_H', 1)
637 elif cc.has_function('gss_store_cred_into', dependencies: gssapi,
638 args: test_c_args, include_directories: postgres_inc)
639 cdata.set('ENABLE_GSS', 1)
641 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
642 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
643 elif gssapiopt.enabled()
644 error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
650 gssapi = not_found_dep
655 ###############################################################
657 ###############################################################
659 ldapopt = get_option('ldap')
660 if ldapopt.disabled()
662 ldap_r = not_found_dep
663 elif host_system == 'windows'
664 ldap = cc.find_library('wldap32', required: ldapopt)
667 # macos framework dependency is buggy for ldap (one can argue whether it's
668 # Apple's or meson's fault), leading to an endless recursion with ldap.h
669 # including itself. See https://github.com/mesonbuild/meson/issues/10002
670 # Luckily we only need pkg-config support, so the workaround isn't
672 ldap = dependency('ldap', method: 'pkg-config', required: false)
675 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
678 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
679 has_headers: 'ldap.h', header_include_directories: postgres_inc)
681 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
682 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
683 # library from a separate OpenLDAP installation). The most reliable
684 # way to check that is to check for a function introduced in 2.5.
686 # don't have ldap, we shouldn't check for ldap_r
687 elif cc.has_function('ldap_verify_credentials',
688 dependencies: ldap, args: test_c_args)
689 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
692 # Use ldap_r for FE if available, else assume ldap is thread-safe.
693 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
694 has_headers: 'ldap.h', header_include_directories: postgres_inc)
695 if not ldap_r.found()
698 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
699 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
702 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
703 # process. Check for OpenLDAP versions known not to tolerate doing so;
704 # assume non-OpenLDAP implementations are safe. The dblink test suite
705 # exercises the hazardous interaction directly.
706 compat_test_code = '''
708 #if !defined(LDAP_VENDOR_VERSION) || \
709 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
710 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
714 if not cc.compiles(compat_test_code,
715 name: 'LDAP implementation compatible',
716 dependencies: ldap, args: test_c_args)
718 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
719 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
720 *** also uses LDAP will crash on exit.''')
725 if ldap.found() and cc.has_function('ldap_initialize',
726 dependencies: ldap, args: test_c_args)
727 cdata.set('HAVE_LDAP_INITIALIZE', 1)
732 assert(ldap_r.found())
733 cdata.set('USE_LDAP', 1)
735 assert(not ldap_r.found())
740 ###############################################################
742 ###############################################################
744 llvmopt = get_option('llvm')
746 if add_languages('cpp', required: llvmopt, native: false)
747 llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
751 cdata.set('USE_LLVM', 1)
753 cpp = meson.get_compiler('cpp')
755 llvm_binpath = llvm.get_variable(configtool: 'bindir')
757 ccache = find_program('ccache', native: true, required: false)
758 clang = find_program(llvm_binpath / 'clang', required: true)
761 message('llvm requires a C++ compiler')
766 ###############################################################
768 ###############################################################
770 icuopt = get_option('icu')
771 if not icuopt.disabled()
772 icu = dependency('icu-uc', required: icuopt)
773 icu_i18n = dependency('icu-i18n', required: icuopt)
776 cdata.set('USE_ICU', 1)
781 icu_i18n = not_found_dep
786 ###############################################################
788 ###############################################################
790 libxmlopt = get_option('libxml')
791 if not libxmlopt.disabled()
792 libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
795 cdata.set('USE_LIBXML', 1)
798 libxml = not_found_dep
803 ###############################################################
805 ###############################################################
807 libxsltopt = get_option('libxslt')
808 if not libxsltopt.disabled()
809 libxslt = dependency('libxslt', required: libxsltopt)
812 cdata.set('USE_LIBXSLT', 1)
815 libxslt = not_found_dep
820 ###############################################################
822 ###############################################################
824 lz4opt = get_option('lz4')
825 if not lz4opt.disabled()
826 lz4 = dependency('liblz4', required: lz4opt)
829 cdata.set('USE_LZ4', 1)
830 cdata.set('HAVE_LIBLZ4', 1)
839 ###############################################################
840 # Library: Tcl (for pltcl)
842 # NB: tclConfig.sh is used in autoconf build for getting
843 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
844 # variables. For now we have not seen a need to copy
845 # that behaviour to the meson build.
846 ###############################################################
848 tclopt = get_option('pltcl')
849 tcl_version = get_option('tcl_version')
850 tcl_dep = not_found_dep
851 if not tclopt.disabled()
854 tcl_dep = dependency(tcl_version, required: false)
856 if not tcl_dep.found()
857 tcl_dep = cc.find_library(tcl_version,
862 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
863 tcl_dep = not_found_dep
869 ###############################################################
871 ###############################################################
873 pamopt = get_option('pam')
874 if not pamopt.disabled()
875 pam = dependency('pam', required: false)
878 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
882 pam_header_found = false
884 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
885 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
886 args: test_c_args, include_directories: postgres_inc)
887 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
888 pam_header_found = true
889 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
890 args: test_c_args, include_directories: postgres_inc)
891 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
892 pam_header_found = true
896 cdata.set('USE_PAM', 1)
907 ###############################################################
908 # Library: Perl (for plperl)
909 ###############################################################
911 perlopt = get_option('plperl')
912 perl_dep = not_found_dep
913 if not perlopt.disabled()
916 # First verify that perl has the necessary dependencies installed
917 perl_mods = run_command(
919 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
922 if perl_mods.returncode() != 0
923 perl_may_work = false
924 perl_msg = 'perl installation does not have the required modules'
927 # Then inquire perl about its configuration
929 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
930 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
931 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
932 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
933 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
935 perl_inc_dir = '@0@/CORE'.format(archlibexp)
937 if perlversion.version_compare('< 5.14')
938 perl_may_work = false
939 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
940 elif useshrplib != 'true'
941 perl_may_work = false
942 perl_msg = 'need a shared perl'
947 # On most platforms, archlibexp is also where the Perl include files live ...
948 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
949 # ... but on newer macOS versions, we must use -iwithsysroot to look
951 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
952 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
953 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
956 # check compiler finds header
957 if not cc.has_header('perl.h', required: false,
958 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
959 perl_may_work = false
960 perl_msg = 'missing perl.h'
965 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
967 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
968 foreach flag : perl_ccflags_r.split(' ')
969 if flag.startswith('-D') and \
970 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
975 if host_system == 'windows'
976 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
978 if cc.get_id() == 'msvc'
979 # prevent binary mismatch between MSVC built plperl and Strawberry or
980 # msys ucrt perl libraries
981 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
985 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
986 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
988 # We are after Embed's ldopts, but without the subset mentioned in
989 # Config's ccdlflags and ldflags. (Those are the choices of those who
990 # built the Perl installation, which are not necessarily appropriate
991 # for building PostgreSQL.)
992 ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
993 undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
994 undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
997 foreach ldopt : ldopts.split(' ')
998 if ldopt == '' or ldopt in undesired
1002 perl_ldopts += ldopt.strip('"')
1005 message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
1006 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1008 perl_dep_int = declare_dependency(
1009 compile_args: perl_ccflags,
1010 link_args: perl_ldopts,
1011 version: perlversion,
1014 # While we're at it, check that we can link to libperl.
1015 # On most platforms, if perl.h is there then libperl.so will be too, but
1016 # at this writing Debian packages them separately.
1017 perl_link_test = '''
1020 #define __inline__ inline
1028 if not cc.links(perl_link_test, name: 'libperl',
1029 args: test_c_args + perl_ccflags + perl_ldopts,
1030 include_directories: postgres_inc)
1031 perl_may_work = false
1032 perl_msg = 'missing libperl'
1035 endif # perl_may_work
1038 perl_dep = perl_dep_int
1040 if perlopt.enabled()
1041 error('dependency plperl failed: @0@'.format(perl_msg))
1043 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1050 ###############################################################
1051 # Library: Python (for plpython)
1052 ###############################################################
1054 pyopt = get_option('plpython')
1055 python3_dep = not_found_dep
1056 if not pyopt.disabled()
1057 pm = import('python')
1058 python3_inst = pm.find_installation(required: pyopt)
1059 if python3_inst.found()
1060 python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1061 # Remove this check after we depend on Meson >= 1.1.0
1062 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt)
1063 python3_dep = not_found_dep
1070 ###############################################################
1072 ###############################################################
1074 if not get_option('readline').disabled()
1075 libedit_preferred = get_option('libedit_preferred')
1076 # Set the order of readline dependencies
1077 check_readline_deps = libedit_preferred ? \
1078 ['libedit', 'readline'] : ['readline', 'libedit']
1080 foreach readline_dep : check_readline_deps
1081 readline = dependency(readline_dep, required: false)
1082 if not readline.found()
1083 readline = cc.find_library(readline_dep,
1084 required: get_option('readline'),
1093 cdata.set('HAVE_LIBREADLINE', 1)
1096 'header_prefix': 'editline/',
1097 'flag_prefix': 'EDITLINE_',
1100 'header_prefix': 'readline/',
1101 'flag_prefix': 'READLINE_',
1104 'header_prefix': '',
1108 # Set the order of prefixes
1109 prefixes = libedit_preferred ? \
1110 [editline_prefix, default_prefix, readline_prefix] : \
1111 [readline_prefix, default_prefix, editline_prefix]
1113 at_least_one_header_found = false
1114 foreach header : ['history', 'readline']
1116 foreach prefix : prefixes
1117 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1118 # Check history.h and readline.h
1119 if not is_found and cc.has_header(header_file,
1120 args: test_c_args, include_directories: postgres_inc,
1121 dependencies: [readline], required: false)
1122 if header == 'readline'
1123 readline_h = header_file
1125 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1127 at_least_one_header_found = true
1132 if not at_least_one_header_found
1133 error('''readline header not found
1134 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1135 failure. It is possible the compiler isn't looking in the proper directory.
1136 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1141 'history_truncate_file',
1142 'rl_completion_matches',
1143 'rl_filename_completion_function',
1144 'rl_reset_screen_size',
1148 foreach func : check_funcs
1149 found = cc.has_function(func, dependencies: [readline],
1150 args: test_c_args, include_directories: postgres_inc)
1151 cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1155 'rl_completion_suppress_quote',
1156 'rl_filename_quote_characters',
1157 'rl_filename_quoting_function',
1160 foreach var : check_vars
1161 cdata.set('HAVE_' + var.to_upper(),
1162 cc.has_header_symbol(readline_h, var,
1163 args: test_c_args, include_directories: postgres_inc,
1164 prefix: '#include <stdio.h>',
1165 dependencies: [readline]) ? 1 : false)
1168 # If found via cc.find_library() ensure headers are found when using the
1169 # dependency. On meson < 0.57 one cannot do compiler checks using the
1170 # dependency returned by declare_dependency(), so we can't do this above.
1171 if readline.type_name() == 'library'
1172 readline = declare_dependency(dependencies: readline,
1173 include_directories: postgres_inc)
1176 # On windows with mingw readline requires auto-import to successfully
1177 # link, as the headers don't use declspec(dllimport)
1178 if host_system == 'windows' and cc.get_id() != 'msvc'
1179 readline = declare_dependency(dependencies: readline,
1180 link_args: '-Wl,--enable-auto-import')
1184 # XXX: Figure out whether to implement mingw warning equivalent
1186 readline = not_found_dep
1191 ###############################################################
1193 ###############################################################
1195 selinux = not_found_dep
1196 selinuxopt = get_option('selinux')
1197 if meson.version().version_compare('>=0.59')
1198 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1200 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1201 cdata.set('HAVE_LIBSELINUX',
1202 selinux.found() ? 1 : false)
1206 ###############################################################
1208 ###############################################################
1210 systemd = not_found_dep
1211 systemdopt = get_option('systemd')
1212 if meson.version().version_compare('>=0.59')
1213 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1215 systemd = dependency('libsystemd', required: systemdopt)
1216 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1220 ###############################################################
1222 ###############################################################
1225 ssl_library = 'none'
1226 sslopt = get_option('ssl')
1228 if sslopt == 'auto' and auto_features.disabled()
1232 if sslopt in ['auto', 'openssl']
1233 openssl_required = (sslopt == 'openssl')
1235 # Try to find openssl via pkg-config et al, if that doesn't work
1236 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1237 # the library names that we know about.
1239 # via pkg-config et al
1240 ssl = dependency('openssl', required: false)
1241 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1242 # we pass cc.find_library() results if necessary
1245 # via library + headers
1247 ssl_lib = cc.find_library('ssl',
1249 header_include_directories: postgres_inc,
1250 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1251 required: openssl_required)
1252 crypto_lib = cc.find_library('crypto',
1254 required: openssl_required)
1255 if ssl_lib.found() and crypto_lib.found()
1256 ssl_int = [ssl_lib, crypto_lib]
1257 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1259 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1260 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1268 ['CRYPTO_new_ex_data', {'required': true}],
1269 ['SSL_new', {'required': true}],
1271 # Functions introduced in OpenSSL 1.0.2.
1272 ['X509_get_signature_nid'],
1273 ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1275 # Functions introduced in OpenSSL 1.1.0. We used to check for
1276 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1277 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1278 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1280 ['OPENSSL_init_ssl'],
1283 ['ASN1_STRING_get0_data'],
1287 # OpenSSL versions before 1.1.0 required setting callback functions, for
1288 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1289 # function was removed.
1292 # Function introduced in OpenSSL 1.1.1
1293 ['X509_get_signature_info'],
1296 are_openssl_funcs_complete = true
1297 foreach c : check_funcs
1299 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1300 required = c.get(1, {}).get('required', false)
1301 if required and not val
1302 are_openssl_funcs_complete = false
1304 error('openssl function @0@ is required'.format(func))
1308 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1312 if are_openssl_funcs_complete
1313 cdata.set('USE_OPENSSL', 1,
1314 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1315 cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1316 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1317 ssl_library = 'openssl'
1324 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1325 error('no SSL library found')
1330 ###############################################################
1332 ###############################################################
1334 uuidopt = get_option('uuid')
1335 if uuidopt != 'none'
1336 uuidname = uuidopt.to_upper()
1337 if uuidopt == 'e2fs'
1338 uuid = dependency('uuid', required: true)
1339 uuidfunc = 'uuid_generate'
1340 uuidheader = 'uuid/uuid.h'
1341 elif uuidopt == 'bsd'
1342 # libc should have uuid function
1343 uuid = declare_dependency()
1344 uuidfunc = 'uuid_to_string'
1345 uuidheader = 'uuid.h'
1346 elif uuidopt == 'ossp'
1347 uuid = dependency('ossp-uuid', required: true)
1348 uuidfunc = 'uuid_export'
1349 uuidheader = 'uuid.h'
1351 error('unknown uuid build option value: @0@'.format(uuidopt))
1354 if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1355 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1357 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1359 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1360 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1362 uuid = not_found_dep
1367 ###############################################################
1369 ###############################################################
1371 zlibopt = get_option('zlib')
1372 zlib = not_found_dep
1373 if not zlibopt.disabled()
1374 zlib_t = dependency('zlib', required: zlibopt)
1376 if zlib_t.type_name() == 'internal'
1377 # if fallback was used, we don't need to test if headers are present (they
1378 # aren't built yet, so we can't test)
1380 elif not zlib_t.found()
1381 warning('did not find zlib')
1382 elif not cc.has_header('zlib.h',
1383 args: test_c_args, include_directories: postgres_inc,
1384 dependencies: [zlib_t], required: zlibopt)
1385 warning('zlib header not found')
1386 elif not cc.has_type('z_streamp',
1387 dependencies: [zlib_t], prefix: '#include <zlib.h>',
1388 args: test_c_args, include_directories: postgres_inc)
1389 if zlibopt.enabled()
1390 error('zlib version is too old')
1392 warning('zlib version is too old')
1399 cdata.set('HAVE_LIBZ', 1)
1405 ###############################################################
1406 # Library: tap test dependencies
1407 ###############################################################
1409 # Check whether tap tests are enabled or not
1410 tap_tests_enabled = false
1411 tapopt = get_option('tap_tests')
1412 if not tapopt.disabled()
1413 # Checking for perl modules for tap tests
1414 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1415 if perl_ipc_run_check.returncode() != 0
1416 message(perl_ipc_run_check.stderr().strip())
1418 error('Additional Perl modules are required to run TAP tests.')
1420 warning('Additional Perl modules are required to run TAP tests.')
1423 tap_tests_enabled = true
1429 ###############################################################
1431 ###############################################################
1433 zstdopt = get_option('zstd')
1434 if not zstdopt.disabled()
1435 zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1438 cdata.set('USE_ZSTD', 1)
1439 cdata.set('HAVE_LIBZSTD', 1)
1443 zstd = not_found_dep
1448 ###############################################################
1450 ###############################################################
1452 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1453 # unnecessarily, because we optionally rely on newer features.
1455 #include <stdbool.h>
1456 #include <complex.h>
1458 #include <inttypes.h>
1460 struct named_init_test {
1465 extern void structfunc(struct named_init_test);
1467 int main(int argc, char **argv)
1469 struct named_init_test nit = {
1474 for (int loop_var = 0; loop_var < 3; loop_var++)
1479 structfunc((struct named_init_test){1, 0});
1485 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1486 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1487 args: test_c_args + ['-std=c99'])
1488 test_c_args += '-std=c99'
1489 cflags += '-std=c99'
1491 error('C compiler does not support C99')
1495 sizeof_long = cc.sizeof('long', args: test_c_args)
1496 cdata.set('SIZEOF_LONG', sizeof_long)
1498 cdata.set('HAVE_LONG_INT_64', 1)
1499 cdata.set('PG_INT64_TYPE', 'long int')
1500 cdata.set_quoted('INT64_MODIFIER', 'l')
1501 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1502 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1503 cdata.set('PG_INT64_TYPE', 'long long int')
1504 cdata.set_quoted('INT64_MODIFIER', 'll')
1506 error('do not know how to get a 64bit int')
1509 if host_machine.endian() == 'big'
1510 cdata.set('WORDS_BIGENDIAN', 1)
1513 alignof_types = ['short', 'int', 'long', 'double']
1515 foreach t : alignof_types
1516 align = cc.alignment(t, args: test_c_args)
1520 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1522 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1524 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1525 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1528 # Check if __int128 is a working 128 bit integer type, and if so
1529 # define PG_INT128_TYPE to that typename.
1531 # This currently only detects a GCC/clang extension, but support for other
1532 # environments may be added in the future.
1534 # For the moment we only test for support for 128bit math; support for
1535 # 128bit literals and snprintf is not required.
1538 * We don't actually run this test, just link it to verify that any support
1539 * functions needed for __int128 are present.
1541 * These are globals to discourage the compiler from folding all the
1542 * arithmetic tests down to compile-time constants. We do not have
1543 * convenient support for 128bit literals at this point...
1545 __int128 a = 48828125;
1546 __int128 b = 97656250;
1551 a = (a << 12) + 1; /* 200000000001 */
1552 b = (b << 12) + 5; /* 400000000005 */
1553 /* try the most relevant arithmetic ops */
1556 /* must use the results, else compiler may optimize arithmetic away */
1562 buggy_int128 = false
1564 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1565 # If not cross-compiling, we can test for bugs and disable use of __int128
1566 # with buggy compilers. If cross-compiling, hope for the best.
1567 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1568 if not meson.is_cross_build()
1570 /* This must match the corresponding code in c.h: */
1571 #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1572 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1573 #elif defined(_MSC_VER)
1574 #define pg_attribute_aligned(a) __declspec(align(a))
1576 typedef __int128 int128a
1577 #if defined(pg_attribute_aligned)
1578 pg_attribute_aligned(8)
1583 void pass_by_val(void *buffer, int128a par) { holder = par; }
1587 long int i64 = 97656225L << 12;
1589 pass_by_val(main, (int128a) i64);
1593 name: '__int128 alignment bug',
1595 assert(r.compiled())
1596 if r.returncode() != 0
1598 message('__int128 support present but buggy and thus disabled')
1603 cdata.set('PG_INT128_TYPE', '__int128')
1604 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1609 # Check if the C compiler knows computed gotos (gcc extension, also
1610 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1612 # Checking whether computed gotos are supported syntax-wise ought to
1613 # be enough, as the syntax is otherwise illegal.
1615 static inline int foo(void)
1617 void *labeladdrs[] = {&&my_label};
1618 goto *labeladdrs[0];
1623 cdata.set('HAVE_COMPUTED_GOTO', 1)
1627 # Check if the C compiler understands _Static_assert(),
1628 # and define HAVE__STATIC_ASSERT if so.
1630 # We actually check the syntax ({ _Static_assert(...) }), because we need
1631 # gcc-style compound expressions to be able to wrap the thing into macros.
1633 int main(int arg, char **argv)
1635 ({ _Static_assert(1, "foo"); });
1639 cdata.set('HAVE__STATIC_ASSERT', 1)
1643 # We use <stdbool.h> if we have it and it declares type bool as having
1644 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1645 if cc.has_type('_Bool', args: test_c_args) \
1646 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1647 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1648 cdata.set('HAVE__BOOL', 1)
1649 cdata.set('PG_USE_STDBOOL', 1)
1653 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1654 # warning for each use of %m.
1655 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1657 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1658 static void call_log(void)
1660 emit_log(0, "error: %s: %m", "foo");
1663 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1664 foreach a : printf_attributes
1665 if cc.compiles(testsrc.format(a),
1666 args: test_c_args + attrib_error_args, name: 'format ' + a)
1667 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1673 if cc.has_function_attribute('visibility:default') and \
1674 cc.has_function_attribute('visibility:hidden')
1675 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1677 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1678 # inlineshidden to C code as well... And either way, we want to put these
1679 # flags into exported files (pgxs, .pc files).
1680 cflags_mod += '-fvisibility=hidden'
1681 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1682 ldflags_mod += '-fvisibility=hidden'
1686 # Check if various builtins exist. Some builtins are tested separately,
1687 # because we want to test something more complicated than the generic case.
1700 foreach builtin : builtins
1701 fname = '__builtin_@0@'.format(builtin)
1702 if cc.has_function(fname, args: test_c_args)
1703 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1708 # Check if the C compiler understands __builtin_types_compatible_p,
1709 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1711 # We check usage with __typeof__, though it's unlikely any compiler would
1712 # have the former and not the latter.
1715 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1717 name: '__builtin_types_compatible_p',
1719 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1723 # Check if the C compiler understands __builtin_$op_overflow(),
1724 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1726 # Check for the most complicated case, 64 bit multiplication, as a
1727 # proxy for all of the operations. To detect the case where the compiler
1728 # knows the function but library support is missing, we must link not just
1729 # compile, and store the results in global variables so the compiler doesn't
1730 # optimize away the call.
1738 return __builtin_mul_overflow(a, b, &result);
1740 name: '__builtin_mul_overflow',
1741 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1743 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1747 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1748 # here. To prevent problems due to two detection methods working, stop
1749 # checking after one.
1752 int main(int arg, char **argv)
1754 unsigned int exx[4] = {0, 0, 0, 0};
1755 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1757 ''', name: '__get_cpuid',
1759 cdata.set('HAVE__GET_CPUID', 1)
1762 int main(int arg, char **argv)
1764 unsigned int exx[4] = {0, 0, 0, 0};
1767 ''', name: '__cpuid',
1769 cdata.set('HAVE__CPUID', 1)
1773 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1774 # versions of clang do not understand -fexcess-precision=standard, the use of
1775 # x87 floating point operations leads to problems like isinf possibly returning
1776 # false for a value that is infinite when converted from the 80bit register to
1777 # the 8byte memory representation.
1779 # Only perform the test if the compiler doesn't understand
1780 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1782 if '-fexcess-precision=standard' not in cflags
1783 if not cc.compiles('''
1784 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1787 name: '', args: test_c_args)
1788 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1794 ###############################################################
1796 ###############################################################
1798 common_functional_flags = [
1799 # Disable strict-aliasing rules; needed for gcc 3.3+
1800 '-fno-strict-aliasing',
1801 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1803 '-fexcess-precision=standard',
1806 cflags += cc.get_supported_arguments(common_functional_flags)
1808 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1811 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1812 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1814 common_warning_flags = [
1815 '-Wmissing-prototypes',
1817 # Really don't want VLAs to be used in our dialect of C
1819 # On macOS, complain about usage of symbols newer than the deployment target
1820 '-Werror=unguarded-availability-new',
1822 '-Wmissing-format-attribute',
1823 '-Wimplicit-fallthrough=3',
1824 '-Wcast-function-type',
1825 '-Wshadow=compatible-local',
1826 # This was included in -Wall/-Wformat in older GCC versions
1827 '-Wformat-security',
1830 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1832 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1835 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1836 # the result for them
1837 cflags_no_decl_after_statement = []
1838 if cc.has_argument('-Wdeclaration-after-statement')
1839 cflags_warn += '-Wdeclaration-after-statement'
1840 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1844 # The following tests want to suppress various unhelpful warnings by adding
1845 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1846 # switches, so we have to test for the positive form and if that works,
1847 # add the negative form.
1849 negative_warning_flags = [
1850 # Suppress clang's unhelpful unused-command-line-argument warnings.
1851 'unused-command-line-argument',
1853 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1854 # of warnings when building plperl because of usages in the Perl headers.
1855 'compound-token-split-by-macro',
1857 # Similarly disable useless truncation warnings from gcc 8+
1858 'format-truncation',
1859 'stringop-truncation',
1861 # Suppress clang 16's strict warnings about function casts
1862 'cast-function-type-strict',
1864 # To make warning_level=2 / -Wextra work, we'd need at least the following
1866 # 'missing-field-initializers',
1868 # 'unused-parameter',
1871 foreach w : negative_warning_flags
1872 if cc.has_argument('-W' + w)
1873 cflags_warn += '-Wno-' + w
1875 if llvm.found() and cpp.has_argument('-W' + w)
1876 cxxflags_warn += '-Wno-' + w
1882 if cc.get_id() == 'msvc'
1884 '/wd4018', # signed/unsigned mismatch
1885 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1886 '/wd4273', # inconsistent DLL linkage
1887 '/wd4101', # unreferenced local variable
1888 '/wd4102', # unreferenced label
1889 '/wd4090', # different 'modifier' qualifiers
1890 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1898 '/D_CRT_SECURE_NO_DEPRECATE',
1899 '/D_CRT_NONSTDC_NO_DEPRECATE',
1902 # We never need export libraries. As link.exe reports their creation, they
1903 # are unnecessarily noisy. Similarly, we don't need import library for
1904 # modules, we only import them dynamically, and they're also noisy.
1906 ldflags_mod += '/NOIMPLIB'
1911 ###############################################################
1913 ###############################################################
1915 if not get_option('spinlocks')
1916 warning('Not using spinlocks will cause poor performance')
1918 cdata.set('HAVE_SPINLOCKS', 1)
1921 if not get_option('atomics')
1922 warning('Not using atomics will cause poor performance')
1924 # XXX: perhaps we should require some atomics support in this case these
1926 cdata.set('HAVE_ATOMICS', 1)
1929 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1930 'desc': '__sync_lock_test_and_set(char)',
1933 __sync_lock_test_and_set(&lock, 1);
1934 __sync_lock_release(&lock);'''},
1936 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1937 'desc': '__sync_lock_test_and_set(int32)',
1940 __sync_lock_test_and_set(&lock, 1);
1941 __sync_lock_release(&lock);'''},
1943 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1944 'desc': '__sync_val_compare_and_swap(int32)',
1947 __sync_val_compare_and_swap(&val, 0, 37);'''},
1949 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1950 'desc': '__sync_val_compare_and_swap(int64)',
1953 __sync_val_compare_and_swap(&val, 0, 37);'''},
1955 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1956 'desc': ' __atomic_compare_exchange_n(int32)',
1960 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1962 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1963 'desc': ' __atomic_compare_exchange_n(int64)',
1967 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1970 foreach check : atomic_checks
1975 }'''.format(check['test'])
1977 cdata.set(check['name'],
1979 name: check['desc'],
1980 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1988 ###############################################################
1989 # Select CRC-32C implementation.
1991 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1992 # use the special CRC instructions for calculating CRC-32C. If we're not
1993 # targeting such a processor, but we can nevertheless produce code that uses
1994 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1995 # implementations and select which one to use at runtime, depending on whether
1996 # SSE 4.2 is supported by the processor we're running on.
1998 # Similarly, if we are targeting an ARM processor that has the CRC
1999 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2000 # we're not targeting such a processor, but can nevertheless produce code that
2001 # uses the CRC instructions, compile both, and select at runtime.
2002 ###############################################################
2004 have_optimized_crc = false
2006 if host_cpu == 'x86' or host_cpu == 'x86_64'
2008 if cc.get_id() == 'msvc'
2009 cdata.set('USE_SSE42_CRC32C', false)
2010 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2011 have_optimized_crc = true
2015 #include <nmmintrin.h>
2019 unsigned int crc = 0;
2020 crc = _mm_crc32_u8(crc, 0);
2021 crc = _mm_crc32_u32(crc, 0);
2022 /* return computed value, to prevent the above being optimized away */
2027 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2029 # Use Intel SSE 4.2 unconditionally.
2030 cdata.set('USE_SSE42_CRC32C', 1)
2031 have_optimized_crc = true
2032 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2033 args: test_c_args + ['-msse4.2'])
2034 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2035 # the runtime check.
2036 cflags_crc += '-msse4.2'
2037 cdata.set('USE_SSE42_CRC32C', false)
2038 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2039 have_optimized_crc = true
2044 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2047 #include <arm_acle.h>
2051 unsigned int crc = 0;
2052 crc = __crc32cb(crc, 0);
2053 crc = __crc32ch(crc, 0);
2054 crc = __crc32cw(crc, 0);
2055 crc = __crc32cd(crc, 0);
2057 /* return computed value, to prevent the above being optimized away */
2062 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2064 # Use ARM CRC Extension unconditionally
2065 cdata.set('USE_ARMV8_CRC32C', 1)
2066 have_optimized_crc = true
2067 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2068 args: test_c_args + ['-march=armv8-a+crc'])
2069 # Use ARM CRC Extension, with runtime check
2070 cflags_crc += '-march=armv8-a+crc'
2071 cdata.set('USE_ARMV8_CRC32C', false)
2072 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2073 have_optimized_crc = true
2077 if not have_optimized_crc
2078 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2080 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2085 ###############################################################
2086 # Other CPU specific stuff
2087 ###############################################################
2089 if host_cpu == 'x86_64'
2094 long long x = 1; long long r;
2095 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2097 name: '@0@: popcntq instruction'.format(host_cpu),
2099 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2102 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2103 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2104 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2107 addi(int ra, int si)
2110 if (__builtin_constant_p(si))
2111 __asm__ __volatile__(
2112 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2115 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2118 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2125 ###############################################################
2126 # Library / OS tests
2127 ###############################################################
2129 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2130 # unnecessary checks over and over, particularly on windows.
2144 'sys/personality.h',
2153 foreach header : header_checks
2154 varname = 'HAVE_' + header.underscorify().to_upper()
2156 # Emulate autoconf behaviour of not-found->undef, found->1
2157 found = cc.has_header(header,
2158 include_directories: postgres_inc, args: test_c_args)
2159 cdata.set(varname, found ? 1 : false,
2160 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2165 ['F_FULLFSYNC', 'fcntl.h'],
2166 ['fdatasync', 'unistd.h'],
2167 ['posix_fadvise', 'fcntl.h'],
2168 ['strlcat', 'string.h'],
2169 ['strlcpy', 'string.h'],
2170 ['strnlen', 'string.h'],
2173 # Need to check for function declarations for these functions, because
2174 # checking for library symbols wouldn't handle deployment target
2175 # restrictions on macOS
2177 ['preadv', 'sys/uio.h'],
2178 ['pwritev', 'sys/uio.h'],
2181 foreach c : decl_checks
2185 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2187 found = cc.has_header_symbol(header, func,
2188 args: test_c_args, include_directories: postgres_inc,
2190 cdata.set10(varname, found, description:
2191 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2192 don't.'''.format(func))
2196 if cc.has_type('struct option',
2197 args: test_c_args, include_directories: postgres_inc,
2198 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2199 cdata.set('HAVE_STRUCT_OPTION', 1)
2203 foreach c : ['opterr', 'optreset']
2204 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2213 '''.format(c), name: c, args: test_c_args)
2214 cdata.set(varname, 1)
2216 cdata.set(varname, false)
2220 if cc.has_type('socklen_t',
2221 args: test_c_args, include_directories: postgres_inc,
2223 #include <sys/socket.h>''')
2224 cdata.set('HAVE_SOCKLEN_T', 1)
2227 if cc.has_member('struct sockaddr', 'sa_len',
2228 args: test_c_args, include_directories: postgres_inc,
2230 #include <sys/types.h>
2231 #include <sys/socket.h>''')
2232 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2235 if cc.has_member('struct tm', 'tm_zone',
2236 args: test_c_args, include_directories: postgres_inc,
2238 #include <sys/types.h>
2241 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2246 extern int foo(void);
2249 return timezone / 60;
2252 name: 'global variable `timezone\' exists',
2253 args: test_c_args, include_directories: postgres_inc)
2254 cdata.set('HAVE_INT_TIMEZONE', 1)
2256 cdata.set('HAVE_INT_TIMEZONE', false)
2259 if cc.has_type('union semun',
2261 include_directories: postgres_inc,
2263 #include <sys/types.h>
2264 #include <sys/ipc.h>
2265 #include <sys/sem.h>
2267 cdata.set('HAVE_UNION_SEMUN', 1)
2275 switch (strerror_r(1, buf, sizeof(buf)))
2276 { case 0: break; default: break; }
2279 args: test_c_args, include_directories: postgres_inc)
2280 cdata.set('STRERROR_R_INT', 1)
2282 cdata.set('STRERROR_R_INT', false)
2285 # Check for the locale_t type and find the right header file. macOS
2286 # needs xlocale.h; standard is locale.h, but glibc also has an
2287 # xlocale.h file that we should not use. MSVC has a replacement
2288 # defined in src/include/port/win32_port.h.
2289 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2290 cdata.set('HAVE_LOCALE_T', 1)
2291 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2292 cdata.set('HAVE_LOCALE_T', 1)
2293 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2294 elif cc.get_id() == 'msvc'
2295 cdata.set('HAVE_LOCALE_T', 1)
2298 # Check if the C compiler understands typeof or a variant. Define
2299 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2300 foreach kw : ['typeof', '__typeof__', 'decltype']
2311 args: test_c_args, include_directories: postgres_inc)
2313 cdata.set('HAVE_TYPEOF', 1)
2315 cdata.set('typeof', kw)
2323 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2324 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2325 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2326 wcstombs_l_test = '''
2338 if (not cc.compiles(wcstombs_l_test.format(''),
2339 name: 'wcstombs_l') and
2340 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2341 name: 'wcstombs_l in xlocale.h'))
2342 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2346 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2347 # understands, because it conflicts with __declspec(restrict). Therefore we
2348 # define pg_restrict to the appropriate definition, which presumably won't
2351 # We assume C99 support, so we don't need to make this conditional.
2353 # XXX: Historically we allowed platforms to disable restrict in template
2354 # files, but that was only added for AIX when building with XLC, which we
2355 # don't support yet.
2356 cdata.set('pg_restrict', '__restrict')
2359 # Most libraries are included only if they demonstrably provide a function we
2360 # need, but libm is an exception: always include it, because there are too
2361 # many compilers that play cute optimization games that will break probes for
2362 # standard functions such as pow().
2363 os_deps += cc.find_library('m', required: false)
2365 rt_dep = cc.find_library('rt', required: false)
2367 dl_dep = cc.find_library('dl', required: false)
2369 util_dep = cc.find_library('util', required: false)
2370 posix4_dep = cc.find_library('posix4', required: false)
2372 getopt_dep = cc.find_library('getopt', required: false)
2373 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2374 # Check if we want to replace getopt/getopt_long even if provided by the system
2375 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2376 # so always use our version on Windows
2377 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2378 # (i.e., allow '-' as a flag character), so use our version on those platforms
2379 # - We want to use system's getopt_long() only if the system provides struct
2381 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2382 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2385 execinfo_dep = cc.find_library('execinfo', required: false)
2387 if host_system == 'cygwin'
2388 cygipc_dep = cc.find_library('cygipc', required: false)
2390 cygipc_dep = not_found_dep
2393 if host_system == 'sunos'
2394 socket_dep = cc.find_library('socket', required: false)
2396 socket_dep = not_found_dep
2399 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2400 # unnecessary checks over and over, particularly on windows.
2402 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2403 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2404 ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2406 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2407 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2408 # required. Just checking for dlsym() ought to suffice.
2409 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2411 ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2413 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2414 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2424 ['posix_fallocate'],
2427 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2428 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2429 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2430 ['setproctitle', {'dependencies': [util_dep]}],
2431 ['setproctitle_fast'],
2432 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2433 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2434 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2435 ['socket', {'dependencies': [socket_dep], 'define': false}],
2437 ['strerror_r', {'dependencies': [thread_dep]}],
2442 ['sync_file_range'],
2448 func_check_results = {}
2449 foreach c : func_checks
2451 kwargs = c.get(1, {})
2452 deps = kwargs.get('dependencies', [])
2454 if kwargs.get('skip', false)
2458 found = cc.has_function(func, args: test_c_args)
2465 found = cc.has_function(func, args: test_c_args,
2466 dependencies: [dep])
2474 func_check_results += {func: found}
2476 if kwargs.get('define', true)
2477 # Emulate autoconf behaviour of not-found->undef, found->1
2478 cdata.set('HAVE_' + func.underscorify().to_upper(),
2480 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2485 if cc.has_function('syslog', args: test_c_args) and \
2486 cc.check_header('syslog.h', args: test_c_args)
2487 cdata.set('HAVE_SYSLOG', 1)
2491 # MSVC has replacements defined in src/include/port/win32_port.h.
2492 if cc.get_id() == 'msvc'
2493 cdata.set('HAVE_WCSTOMBS_L', 1)
2494 cdata.set('HAVE_MBSTOWCS_L', 1)
2498 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2500 if sema_kind == 'unnamed_posix' and \
2501 not func_check_results.get('sem_init', false)
2505 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2506 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2508 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2509 cdata.set_quoted('DLSUFFIX', dlsuffix)
2512 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2513 cdata.set_quoted('PG_VERSION_STR',
2514 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2515 pg_version, host_machine.cpu_family(), host_system,
2516 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2522 ###############################################################
2524 ###############################################################
2526 # XXX: About to rely on thread safety in the autoconf build, so not worth
2527 # implementing a fallback.
2528 cdata.set('ENABLE_THREAD_SAFETY', 1)
2532 ###############################################################
2534 ###############################################################
2536 nlsopt = get_option('nls')
2537 libintl = not_found_dep
2539 if not nlsopt.disabled()
2540 # otherwise there'd be lots of
2541 # "Gettext not found, all translation (po) targets will be ignored."
2542 # warnings if not found.
2543 msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2545 # meson 0.59 has this wrapped in dependency('intl')
2546 if (msgfmt.found() and
2547 cc.check_header('libintl.h', required: nlsopt,
2548 args: test_c_args, include_directories: postgres_inc))
2551 if cc.has_function('ngettext')
2552 libintl = declare_dependency()
2554 libintl = cc.find_library('intl',
2555 has_headers: ['libintl.h'], required: nlsopt,
2556 header_include_directories: postgres_inc,
2562 i18n = import('i18n')
2563 cdata.set('ENABLE_NLS', 1)
2569 ###############################################################
2571 ###############################################################
2573 # Set up compiler / linker arguments to be used everywhere, individual targets
2574 # can add further args directly, or indirectly via dependencies
2575 add_project_arguments(cflags, language: ['c'])
2576 add_project_arguments(cppflags, language: ['c'])
2577 add_project_arguments(cflags_warn, language: ['c'])
2578 add_project_arguments(cxxflags, language: ['cpp'])
2579 add_project_arguments(cppflags, language: ['cpp'])
2580 add_project_arguments(cxxflags_warn, language: ['cpp'])
2581 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2584 # Collect a number of lists of things while recursing through the source
2585 # tree. Later steps then can use those.
2587 # list of targets for various alias targets
2588 backend_targets = []
2591 contrib_targets = []
2592 testprep_targets = []
2596 # Define the tests to distribute them to the correct test styles later
2601 # Default options for targets
2603 # First identify rpaths
2604 bin_install_rpaths = []
2605 lib_install_rpaths = []
2606 mod_install_rpaths = []
2609 # Don't add rpaths on darwin for now - as long as only absolute references to
2610 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2611 # their final destination.
2612 if host_system != 'darwin'
2613 # Add absolute path to libdir to rpath. This ensures installed binaries /
2614 # libraries find our libraries (mainly libpq).
2615 bin_install_rpaths += dir_prefix / dir_lib
2616 lib_install_rpaths += dir_prefix / dir_lib
2617 mod_install_rpaths += dir_prefix / dir_lib
2619 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2621 # Not needed on darwin even if we use relative rpaths for our own libraries,
2622 # as the install_name of libraries in extra_lib_dirs will point to their
2624 bin_install_rpaths += postgres_lib_d
2625 lib_install_rpaths += postgres_lib_d
2626 mod_install_rpaths += postgres_lib_d
2630 # Define arguments for default targets
2632 default_target_args = {
2633 'implicit_include_directories': false,
2637 default_lib_args = default_target_args + {
2641 internal_lib_args = default_lib_args + {
2642 'build_by_default': false,
2646 default_mod_args = default_lib_args + {
2648 'install_dir': dir_lib_pkg,
2651 default_bin_args = default_target_args + {
2652 'install_dir': dir_bin,
2655 if get_option('rpath')
2656 default_lib_args += {
2657 'install_rpath': ':'.join(lib_install_rpaths),
2660 default_mod_args += {
2661 'install_rpath': ':'.join(mod_install_rpaths),
2664 default_bin_args += {
2665 'install_rpath': ':'.join(bin_install_rpaths),
2670 # Helper for exporting a limited number of symbols
2671 gen_export_kwargs = {
2672 'input': 'exports.txt',
2673 'output': '@BASENAME@.'+export_file_suffix,
2674 'command': [perl, files('src/tools/gen_export.pl'),
2675 '--format', export_file_format,
2676 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2677 'build_by_default': false,
2684 ### Helpers for custom targets used across the tree
2687 catalog_pm = files('src/backend/catalog/Catalog.pm')
2688 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2689 gen_kwlist_deps = [perfect_hash_pm]
2691 perl, '-I', '@SOURCE_ROOT@/src/tools',
2692 files('src/tools/gen_keywordlist.pl'),
2693 '--output', '@OUTDIR@', '@INPUT@']
2698 ### windows resources related stuff
2701 if host_system == 'windows'
2702 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2703 win32ver_rc = files('src/port/win32ver.rc')
2704 rcgen = find_program('src/tools/rcgen', native: true)
2707 '--srcdir', '@SOURCE_DIR@',
2708 '--builddir', meson.build_root(),
2709 '--rcout', '@OUTPUT0@',
2710 '--out', '@OUTPUT1@',
2711 '--input', '@INPUT@',
2715 if cc.get_argument_syntax() == 'msvc'
2716 rc = find_program('rc', required: true)
2717 rcgen_base_args += ['--rc', rc.path()]
2718 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2720 windres = find_program('windres', required: true)
2721 rcgen_base_args += ['--windres', windres.path()]
2722 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2725 # msbuild backend doesn't support this atm
2726 if meson.backend() == 'ninja'
2727 rcgen_base_args += ['--depfile', '@DEPFILE@']
2730 rcgen_bin_args = rcgen_base_args + [
2731 '--VFT_TYPE', 'VFT_APP',
2732 '--FILEENDING', 'exe',
2736 rcgen_lib_args = rcgen_base_args + [
2737 '--VFT_TYPE', 'VFT_DLL',
2738 '--FILEENDING', 'dll',
2741 rc_bin_gen = generator(rcgen,
2742 depfile: '@BASENAME@.d',
2743 arguments: rcgen_bin_args,
2744 output: rcgen_outputs,
2747 rc_lib_gen = generator(rcgen,
2748 depfile: '@BASENAME@.d',
2749 arguments: rcgen_lib_args,
2750 output: rcgen_outputs,
2756 # headers that the whole build tree depends on
2757 generated_headers = []
2758 # headers that the backend build depends on
2759 generated_backend_headers = []
2760 # configure_files() output, needs a way of converting to file names
2761 configure_files = []
2763 # generated files that might conflict with a partial in-tree autoconf build
2764 generated_sources = []
2765 # same, for paths that differ between autoconf / meson builds
2766 # elements are [dir, [files]]
2767 generated_sources_ac = {}
2770 # First visit src/include - all targets creating headers are defined
2771 # within. That makes it easy to add the necessary dependencies for the
2772 # subsequent build steps.
2774 subdir('src/include')
2778 # Then through src/port and src/common, as most other things depend on them
2780 frontend_port_code = declare_dependency(
2781 compile_args: ['-DFRONTEND'],
2782 include_directories: [postgres_inc],
2783 dependencies: os_deps,
2786 backend_port_code = declare_dependency(
2787 compile_args: ['-DBUILDING_DLL'],
2788 include_directories: [postgres_inc],
2789 sources: [errcodes], # errcodes.h is needed due to use of ereport
2790 dependencies: os_deps,
2795 frontend_common_code = declare_dependency(
2796 compile_args: ['-DFRONTEND'],
2797 include_directories: [postgres_inc],
2798 sources: generated_headers,
2799 dependencies: [os_deps, zlib, zstd],
2802 backend_common_code = declare_dependency(
2803 compile_args: ['-DBUILDING_DLL'],
2804 include_directories: [postgres_inc],
2805 sources: generated_headers,
2806 dependencies: [os_deps, zlib, zstd],
2809 subdir('src/common')
2811 # all shared libraries should depend on shlib_code
2812 shlib_code = declare_dependency(
2813 link_args: ldflags_sl,
2816 # all static libraries not part of the backend should depend on this
2817 frontend_stlib_code = declare_dependency(
2818 include_directories: [postgres_inc],
2819 link_with: [common_static, pgport_static],
2820 sources: generated_headers,
2821 dependencies: [os_deps, libintl],
2824 # all shared libraries not part of the backend should depend on this
2825 frontend_shlib_code = declare_dependency(
2826 include_directories: [postgres_inc],
2827 link_with: [common_shlib, pgport_shlib],
2828 sources: generated_headers,
2829 dependencies: [shlib_code, os_deps, libintl],
2832 # Dependencies both for static and shared libpq
2842 subdir('src/interfaces/libpq')
2843 # fe_utils depends on libpq
2844 subdir('src/fe_utils')
2846 # for frontend binaries
2847 frontend_code = declare_dependency(
2848 include_directories: [postgres_inc],
2849 link_with: [fe_utils, common_static, pgport_static],
2850 sources: generated_headers,
2851 dependencies: [os_deps, libintl],
2854 backend_both_deps += [
2871 backend_mod_deps = backend_both_deps + os_deps
2873 backend_code = declare_dependency(
2874 compile_args: ['-DBUILDING_DLL'],
2875 include_directories: [postgres_inc],
2876 link_args: ldflags_be,
2878 sources: generated_headers + generated_backend_headers,
2879 dependencies: os_deps + backend_both_deps + backend_deps,
2882 # install these files only during test, not main install
2883 test_install_data = []
2884 test_install_libs = []
2886 # src/backend/meson.build defines backend_mod_code used for extension
2890 # Then through the main sources. That way contrib can have dependencies on
2891 # main sources. Note that this explicitly doesn't enter src/test, right now a
2892 # few regression tests depend on contrib files.
2899 subdir('src/interfaces/libpq/test')
2900 subdir('src/interfaces/ecpg/test')
2902 subdir('doc/src/sgml')
2904 generated_sources_ac += {'': ['GNUmakefile']}
2906 # After processing src/test, add test_install_libs to the testprep_targets
2908 testprep_targets += test_install_libs
2911 # If there are any files in the source directory that we also generate in the
2912 # build directory, they might get preferred over the newly generated files,
2913 # e.g. because of a #include "file", which always will search in the current
2915 message('checking for file conflicts between source and build directory')
2916 conflicting_files = []
2917 potentially_conflicting_files_t = []
2918 potentially_conflicting_files_t += generated_headers
2919 potentially_conflicting_files_t += generated_backend_headers
2920 potentially_conflicting_files_t += generated_backend_sources
2921 potentially_conflicting_files_t += generated_sources
2923 potentially_conflicting_files = []
2925 # convert all sources of potentially conflicting files into uniform shape
2926 foreach t : potentially_conflicting_files_t
2927 potentially_conflicting_files += t.full_path()
2929 foreach t : configure_files
2931 potentially_conflicting_files += meson.current_build_dir() / t
2933 foreach sub, fnames : generated_sources_ac
2934 sub = meson.build_root() / sub
2935 foreach fname : fnames
2936 potentially_conflicting_files += sub / fname
2940 # find and report conflicting files
2941 foreach build_path : potentially_conflicting_files
2942 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2943 # str.replace is in 0.56
2944 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2945 if fs.exists(src_path) or fs.is_symlink(src_path)
2946 conflicting_files += src_path
2949 # XXX: Perhaps we should generate a file that would clean these up? The list
2951 if conflicting_files.length() > 0
2952 errmsg_cleanup = '''
2953 Conflicting files in source directory:
2956 The conflicting files need to be removed, either by removing the files listed
2957 above, or by running configure and then make maintainer-clean.
2959 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2960 error(errmsg_nonclean_base.format(errmsg_cleanup))
2965 ###############################################################
2967 ###############################################################
2970 # We want to define additional install targets beyond what meson provides. For
2971 # that we need to define targets depending on nearly everything. We collected
2972 # the results of i18n.gettext() invocations into nls_targets, that also
2973 # includes maintainer targets though. Collect the ones we want as a dependency.
2975 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
2976 # generation happens during install, so that's not a real issue.
2978 if libintl.found() and meson.version().version_compare('>=0.60')
2979 # use range() to avoid the flattening of the list that foreach() would do
2980 foreach off : range(0, nls_targets.length())
2981 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
2982 # -pot target 3) maintainer -pot target
2983 nls_mo_targets += nls_targets[off][0]
2985 alias_target('nls', nls_mo_targets)
3000 # Meson's default install target is quite verbose. Provide one that is quiet.
3001 install_quiet = custom_target('install-quiet',
3002 output: 'install-quiet',
3003 build_always_stale: true,
3004 build_by_default: false,
3005 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3009 # Target to install files used for tests, which aren't installed by default
3010 install_test_files_args = [
3012 '--prefix', dir_prefix,
3013 '--install', contrib_data_dir, test_install_data,
3014 '--install', dir_lib_pkg, test_install_libs,
3016 run_target('install-test-files',
3017 command: [python] + install_test_files_args,
3018 depends: testprep_targets,
3023 ###############################################################
3025 ###############################################################
3027 # DESTDIR for the installation we'll run tests in
3028 test_install_destdir = meson.build_root() / 'tmp_install/'
3030 # DESTDIR + prefix appropriately munged
3031 if build_system != 'windows'
3032 # On unixoid systems this is trivial, we just prepend the destdir
3033 assert(dir_prefix.startswith('/')) # enforced by meson
3034 test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3036 # drives, drive-relative paths, etc make this complicated on windows, call
3037 # into a copy of meson's logic for it
3040 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3041 test_install_destdir, dir_prefix]
3042 test_install_location = run_command(command, check: true).stdout().strip()
3045 meson_install_args = meson_args + ['install'] + {
3046 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3050 # setup tests should be run first,
3051 # so define priority for these
3052 setup_tests_priority = 100
3054 meson_bin, args: meson_install_args ,
3055 env: {'DESTDIR':test_install_destdir},
3056 priority: setup_tests_priority,
3061 test('install_test_files',
3063 args: install_test_files_args + ['--destdir', test_install_destdir],
3064 priority: setup_tests_priority,
3068 test_result_dir = meson.build_root() / 'testrun'
3071 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3072 # inevitable conflicts from running tests in parallel, hackishly assign
3073 # different ports for different tests.
3077 test_env = environment()
3079 temp_install_bindir = test_install_location / get_option('bindir')
3080 test_env.set('PG_REGRESS', pg_regress.full_path())
3081 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3083 # Test suites that are not safe by default but can be run if selected
3084 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3085 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3086 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3088 # Add the temporary installation to the library search path on platforms where
3089 # that works (everything but windows, basically). On windows everything
3090 # library-like gets installed into bindir, solving that issue.
3091 if library_path_var != ''
3092 test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3097 ###############################################################
3099 ###############################################################
3101 # When using a meson version understanding exclude_suites, define a
3102 # 'tmp_install' test setup (the default) that excludes tests running against a
3103 # pre-existing install and a 'running' setup that conflicts with creation of
3104 # the temporary installation and tap tests (which don't support running
3105 # against a running server).
3109 if meson.version().version_compare('>=0.57')
3112 runningcheck = false
3115 testwrap = files('src/tools/testwrap')
3117 foreach test_dir : tests
3120 '--basedir', meson.build_root(),
3121 '--srcdir', test_dir['sd'],
3124 foreach kind, v : test_dir
3125 if kind in ['sd', 'bd', 'name']
3131 if kind in ['regress', 'isolation', 'ecpg']
3132 if kind == 'regress'
3134 fallback_dbname = 'regression_@0@'
3135 elif kind == 'isolation'
3136 runner = pg_isolation_regress
3137 fallback_dbname = 'isolation_regression_@0@'
3139 runner = pg_regress_ecpg
3140 fallback_dbname = 'ecpg_regression_@0@'
3143 test_group = test_dir['name']
3144 test_group_running = test_dir['name'] + '-running'
3146 test_output = test_result_dir / test_group / kind
3147 test_output_running = test_result_dir / test_group_running/ kind
3149 # Unless specified by the test, choose a non-conflicting database name,
3150 # to avoid conflicts when running against existing server.
3151 dbname = t.get('dbname',
3152 fallback_dbname.format(test_dir['name']))
3154 test_command_base = [
3156 '--inputdir', t.get('inputdir', test_dir['sd']),
3157 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3159 '--dlpath', test_dir['bd'],
3160 '--max-concurrent-tests=20',
3162 ] + t.get('regress_args', [])
3165 if t.has_key('schedule')
3166 test_selection += ['--schedule', t['schedule'],]
3169 if kind == 'isolation'
3170 test_selection += t.get('specs', [])
3172 test_selection += t.get('sql', [])
3176 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3182 'depends': test_deps + t.get('deps', []),
3184 } + t.get('test_kwargs', {})
3186 test(test_group / kind,
3190 '--testgroup', test_group,
3194 '--outputdir', test_output,
3195 '--temp-instance', test_output / 'tmp_check',
3196 '--port', testport.to_string(),
3200 kwargs: test_kwargs,
3202 install_suites += test_group
3204 # some tests can't support running against running DB
3205 if runningcheck and t.get('runningcheck', true)
3206 test(test_group_running / kind,
3210 '--testgroup', test_group_running,
3214 '--outputdir', test_output_running,
3217 is_parallel: t.get('runningcheck-parallel', true),
3218 suite: test_group_running,
3219 kwargs: test_kwargs,
3221 running_suites += test_group_running
3226 if not tap_tests_enabled
3232 '-I', meson.source_root() / 'src/test/perl',
3233 '-I', test_dir['sd'],
3236 # Add temporary install, the build directory for non-installed binaries and
3237 # also test/ for non-installed test binaries built separately.
3239 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3241 foreach name, value : t.get('env', {})
3242 env.set(name, value)
3245 test_group = test_dir['name']
3248 'suite': test_group,
3250 'depends': test_deps + t.get('deps', []),
3252 } + t.get('test_kwargs', {})
3254 foreach onetap : t['tests']
3255 # Make tap test names prettier, remove t/ and .pl
3257 if onetap_p.startswith('t/')
3258 onetap_p = onetap.split('t/')[1]
3260 if onetap_p.endswith('.pl')
3261 onetap_p = fs.stem(onetap_p)
3264 test(test_dir['name'] / onetap_p,
3266 kwargs: test_kwargs,
3267 args: testwrap_base + [
3268 '--testgroup', test_dir['name'],
3269 '--testname', onetap_p,
3271 test_dir['sd'] / onetap,
3275 install_suites += test_group
3277 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3280 endforeach # kinds of tests
3282 endforeach # directories with tests
3284 # repeat condition so meson realizes version dependency
3285 if meson.version().version_compare('>=0.57')
3286 add_test_setup('tmp_install',
3288 exclude_suites: running_suites)
3289 add_test_setup('running',
3290 exclude_suites: ['setup'] + install_suites)
3295 ###############################################################
3297 ###############################################################
3299 alias_target('backend', backend_targets)
3300 alias_target('bin', bin_targets + [libpq_st])
3301 alias_target('pl', pl_targets)
3302 alias_target('contrib', contrib_targets)
3303 alias_target('testprep', testprep_targets)
3304 alias_target('install-world', install_quiet, installdocs)
3308 ###############################################################
3309 # The End, The End, My Friend
3310 ###############################################################
3312 if meson.version().version_compare('>=0.57')
3316 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3317 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3318 'segment size': get_option('segsize_blocks') != 0 ?
3319 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3320 '@0@ GB'.format(get_option('segsize')),
3322 section: 'Data layout',
3327 'host system': '@0@ @1@'.format(host_system, host_cpu),
3328 'build system': '@0@ @1@'.format(build_machine.system(),
3329 build_machine.cpu_family()),
3336 'linker': '@0@'.format(cc.get_linker_id()),
3337 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3339 section: 'Compiler',
3344 'CPP FLAGS': ' '.join(cppflags),
3345 'C FLAGS, functional': ' '.join(cflags),
3346 'C FLAGS, warnings': ' '.join(cflags_warn),
3347 'C FLAGS, modules': ' '.join(cflags_mod),
3348 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3349 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3351 section: 'Compiler Flags',
3357 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3359 section: 'Compiler',
3364 'C++ FLAGS, functional': ' '.join(cxxflags),
3365 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3366 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3368 section: 'Compiler Flags',
3374 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3377 section: 'Programs',
3383 'bsd_auth': bsd_auth,
3385 'docs_pdf': docs_pdf_dep,
3397 'plpython': python3_dep,
3399 'readline': readline,
3406 section: 'External libraries',