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 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 = '-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.returncode() != 0 or 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 = dependency('', required : false)
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.has_function('gss_init_sec_context', dependencies: gssapi,
628 args: test_c_args, include_directories: postgres_inc)
629 cdata.set('ENABLE_GSS', 1)
631 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
632 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
633 elif gssapiopt.enabled()
634 error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
640 gssapi = not_found_dep
645 ###############################################################
647 ###############################################################
649 ldapopt = get_option('ldap')
650 if ldapopt.disabled()
652 ldap_r = not_found_dep
653 elif host_system == 'windows'
654 ldap = cc.find_library('wldap32', required: ldapopt)
657 # macos framework dependency is buggy for ldap (one can argue whether it's
658 # Apple's or meson's fault), leading to an endless recursion with ldap.h
659 # including itself. See https://github.com/mesonbuild/meson/issues/10002
660 # Luckily we only need pkg-config support, so the workaround isn't
662 ldap = dependency('ldap', method: 'pkg-config', required: false)
665 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
668 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
669 has_headers: 'ldap.h', header_include_directories: postgres_inc)
671 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
672 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
673 # library from a separate OpenLDAP installation). The most reliable
674 # way to check that is to check for a function introduced in 2.5.
676 # don't have ldap, we shouldn't check for ldap_r
677 elif cc.has_function('ldap_verify_credentials',
678 dependencies: ldap, args: test_c_args)
679 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
682 # Use ldap_r for FE if available, else assume ldap is thread-safe.
683 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
684 has_headers: 'ldap.h', header_include_directories: postgres_inc)
685 if not ldap_r.found()
688 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
689 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
692 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
693 # process. Check for OpenLDAP versions known not to tolerate doing so;
694 # assume non-OpenLDAP implementations are safe. The dblink test suite
695 # exercises the hazardous interaction directly.
696 compat_test_code = '''
698 #if !defined(LDAP_VENDOR_VERSION) || \
699 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
700 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
704 if not cc.compiles(compat_test_code,
705 name: 'LDAP implementation compatible',
706 dependencies: ldap, args: test_c_args)
708 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
709 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
710 *** also uses LDAP will crash on exit.''')
715 # XXX: this shouldn't be tested in the windows case, but should be tested in
716 # the dependency() success case
717 if ldap.found() and cc.has_function('ldap_initialize',
718 dependencies: ldap, args: test_c_args)
719 cdata.set('HAVE_LDAP_INITIALIZE', 1)
724 assert(ldap_r.found())
725 cdata.set('USE_LDAP', 1)
727 assert(not ldap_r.found())
732 ###############################################################
734 ###############################################################
736 llvmopt = get_option('llvm')
737 if not llvmopt.disabled()
738 add_languages('cpp', required: true, native: false)
739 llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
743 cdata.set('USE_LLVM', 1)
745 cpp = meson.get_compiler('cpp')
747 llvm_binpath = llvm.get_variable(configtool: 'bindir')
749 ccache = find_program('ccache', native: true, required: false)
750 clang = find_program(llvm_binpath / 'clang', required: true)
758 ###############################################################
760 ###############################################################
762 icuopt = get_option('icu')
763 if not icuopt.disabled()
764 icu = dependency('icu-uc', required: icuopt.enabled())
765 icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
768 cdata.set('USE_ICU', 1)
773 icu_i18n = not_found_dep
778 ###############################################################
780 ###############################################################
782 libxmlopt = get_option('libxml')
783 if not libxmlopt.disabled()
784 libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
787 cdata.set('USE_LIBXML', 1)
790 libxml = not_found_dep
795 ###############################################################
797 ###############################################################
799 libxsltopt = get_option('libxslt')
800 if not libxsltopt.disabled()
801 libxslt = dependency('libxslt', required: libxsltopt)
804 cdata.set('USE_LIBXSLT', 1)
807 libxslt = not_found_dep
812 ###############################################################
814 ###############################################################
816 lz4opt = get_option('lz4')
817 if not lz4opt.disabled()
818 lz4 = dependency('liblz4', required: lz4opt)
821 cdata.set('USE_LZ4', 1)
822 cdata.set('HAVE_LIBLZ4', 1)
831 ###############################################################
832 # Library: Tcl (for pltcl)
834 # NB: tclConfig.sh is used in autoconf build for getting
835 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
836 # variables. For now we have not seen a need to copy
837 # that behaviour to the meson build.
838 ###############################################################
840 tclopt = get_option('pltcl')
841 tcl_version = get_option('tcl_version')
842 tcl_dep = not_found_dep
843 if not tclopt.disabled()
846 tcl_dep = dependency(tcl_version, required: false)
848 if not tcl_dep.found()
849 tcl_dep = cc.find_library(tcl_version,
854 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
855 tcl_dep = not_found_dep
861 ###############################################################
863 ###############################################################
865 pamopt = get_option('pam')
866 if not pamopt.disabled()
867 pam = dependency('pam', required: false)
870 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
874 pam_header_found = false
876 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
877 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
878 args: test_c_args, include_directories: postgres_inc)
879 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
880 pam_header_found = true
881 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
882 args: test_c_args, include_directories: postgres_inc)
883 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
884 pam_header_found = true
888 cdata.set('USE_PAM', 1)
899 ###############################################################
900 # Library: Perl (for plperl)
901 ###############################################################
903 perlopt = get_option('plperl')
904 perl_dep = not_found_dep
905 if not perlopt.disabled()
908 # First verify that perl has the necessary dependencies installed
909 perl_mods = run_command(
911 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
914 if perl_mods.returncode() != 0
915 perl_may_work = false
916 perl_msg = 'perl installation does not have the required modules'
919 # Then inquire perl about its configuration
921 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
922 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
923 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
924 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
925 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
927 perl_inc_dir = '@0@/CORE'.format(archlibexp)
929 if perlversion.version_compare('< 5.14')
930 perl_may_work = false
931 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
932 elif useshrplib != 'true'
933 perl_may_work = false
934 perl_msg = 'need a shared perl'
939 # On most platforms, archlibexp is also where the Perl include files live ...
940 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
941 # ... but on newer macOS versions, we must use -iwithsysroot to look
943 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
944 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
945 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
948 # check compiler finds header
949 if not cc.has_header('perl.h', required: false,
950 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
951 perl_may_work = false
952 perl_msg = 'missing perl.h'
957 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
959 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
960 foreach flag : perl_ccflags_r.split(' ')
961 if flag.startswith('-D') and \
962 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
967 if host_system == 'windows'
968 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
970 if cc.get_id() == 'msvc'
971 # prevent binary mismatch between MSVC built plperl and Strawberry or
972 # msys ucrt perl libraries
973 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
977 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
978 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
980 # We are after Embed's ldopts, but without the subset mentioned in
981 # Config's ccdlflags and ldflags. (Those are the choices of those who
982 # built the Perl installation, which are not necessarily appropriate
983 # for building PostgreSQL.)
984 ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
985 undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
986 undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
989 foreach ldopt : ldopts.split(' ')
990 if ldopt == '' or ldopt in undesired
994 perl_ldopts += ldopt.strip('"')
997 message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
998 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1000 perl_dep_int = declare_dependency(
1001 compile_args: perl_ccflags,
1002 link_args: perl_ldopts,
1003 version: perlversion,
1006 # While we're at it, check that we can link to libperl.
1007 # On most platforms, if perl.h is there then libperl.so will be too, but
1008 # at this writing Debian packages them separately.
1009 perl_link_test = '''
1012 #define __inline__ inline
1020 if not cc.links(perl_link_test, name: 'libperl',
1021 args: test_c_args + perl_ccflags + perl_ldopts,
1022 include_directories: postgres_inc)
1023 perl_may_work = false
1024 perl_msg = 'missing libperl'
1027 endif # perl_may_work
1030 perl_dep = perl_dep_int
1032 if perlopt.enabled()
1033 error('dependency plperl failed: @0@'.format(perl_msg))
1035 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1042 ###############################################################
1043 # Library: Python (for plpython)
1044 ###############################################################
1046 pyopt = get_option('plpython')
1047 if not pyopt.disabled()
1048 pm = import('python')
1049 python3_inst = pm.find_installation(required: pyopt.enabled())
1050 python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
1051 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
1052 python3_dep = not_found_dep
1055 python3_dep = not_found_dep
1060 ###############################################################
1062 ###############################################################
1064 if not get_option('readline').disabled()
1065 libedit_preferred = get_option('libedit_preferred')
1066 # Set the order of readline dependencies
1067 check_readline_deps = libedit_preferred ? \
1068 ['libedit', 'readline'] : ['readline', 'libedit']
1070 foreach readline_dep : check_readline_deps
1071 readline = dependency(readline_dep, required: false)
1072 if not readline.found()
1073 readline = cc.find_library(readline_dep,
1074 required: get_option('readline').enabled(),
1083 cdata.set('HAVE_LIBREADLINE', 1)
1086 'header_prefix': 'editline/',
1087 'flag_prefix': 'EDITLINE_',
1090 'header_prefix': 'readline/',
1091 'flag_prefix': 'READLINE_',
1094 'header_prefix': '',
1098 # Set the order of prefixes
1099 prefixes = libedit_preferred ? \
1100 [editline_prefix, default_prefix, readline_prefix] : \
1101 [readline_prefix, default_prefix, editline_prefix]
1103 at_least_one_header_found = false
1104 foreach header : ['history', 'readline']
1106 foreach prefix : prefixes
1107 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1108 # Check history.h and readline.h
1109 if not is_found and cc.has_header(header_file,
1110 args: test_c_args, include_directories: postgres_inc,
1111 dependencies: [readline], required: false)
1112 if header == 'readline'
1113 readline_h = header_file
1115 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1117 at_least_one_header_found = true
1122 if not at_least_one_header_found
1123 error('''readline header not found
1124 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1125 failure. It is possible the compiler isn't looking in the proper directory.
1126 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1131 'history_truncate_file',
1132 'rl_completion_matches',
1133 'rl_filename_completion_function',
1134 'rl_reset_screen_size',
1138 foreach func : check_funcs
1139 found = cc.has_function(func, dependencies: [readline],
1140 args: test_c_args, include_directories: postgres_inc)
1141 cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1145 'rl_completion_suppress_quote',
1146 'rl_filename_quote_characters',
1147 'rl_filename_quoting_function',
1150 foreach var : check_vars
1151 cdata.set('HAVE_'+var.to_upper(),
1152 cc.has_header_symbol(readline_h, var,
1153 args: test_c_args, include_directories: postgres_inc,
1154 prefix: '#include <stdio.h>',
1155 dependencies: [readline]) ? 1 : false)
1158 # If found via cc.find_library() ensure headers are found when using the
1159 # dependency. On meson < 0.57 one cannot do compiler checks using the
1160 # dependency returned by declare_dependency(), so we can't do this above.
1161 if readline.type_name() == 'library'
1162 readline = declare_dependency(dependencies: readline,
1163 include_directories: postgres_inc)
1166 # On windows with mingw readline requires auto-import to successfully
1167 # link, as the headers don't use declspec(dllimport)
1168 if host_system == 'windows' and cc.get_id() != 'msvc'
1169 readline = declare_dependency(dependencies: readline,
1170 link_args: '-Wl,--enable-auto-import')
1174 # XXX: Figure out whether to implement mingw warning equivalent
1176 readline = not_found_dep
1181 ###############################################################
1183 ###############################################################
1185 selinux = not_found_dep
1186 selinuxopt = get_option('selinux')
1187 if meson.version().version_compare('>=0.59')
1188 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1190 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1191 cdata.set('HAVE_LIBSELINUX',
1192 selinux.found() ? 1 : false)
1196 ###############################################################
1198 ###############################################################
1200 systemd = not_found_dep
1201 systemdopt = get_option('systemd')
1202 if meson.version().version_compare('>=0.59')
1203 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1205 systemd = dependency('libsystemd', required: systemdopt)
1206 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1210 ###############################################################
1212 ###############################################################
1215 ssl_library = 'none'
1216 sslopt = get_option('ssl')
1218 if sslopt == 'auto' and auto_features.disabled()
1222 if sslopt in ['auto', 'openssl']
1223 openssl_required = (sslopt == 'openssl')
1225 # Try to find openssl via pkg-config et al, if that doesn't work
1226 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1227 # the library names that we know about.
1229 # via pkg-config et al
1230 ssl = dependency('openssl', required: false)
1231 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1232 # we pass cc.find_library() results if necessary
1235 # via library + headers
1237 ssl_lib = cc.find_library('ssl',
1239 header_include_directories: postgres_inc,
1240 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1241 required: openssl_required)
1242 crypto_lib = cc.find_library('crypto',
1244 required: openssl_required)
1245 if ssl_lib.found() and crypto_lib.found()
1246 ssl_int = [ssl_lib, crypto_lib]
1247 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1249 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1250 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1258 ['CRYPTO_new_ex_data', {'required': true}],
1259 ['SSL_new', {'required': true}],
1261 # Functions introduced in OpenSSL 1.0.2.
1262 ['X509_get_signature_nid'],
1263 ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1265 # Functions introduced in OpenSSL 1.1.0. We used to check for
1266 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1267 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1268 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1270 ['OPENSSL_init_ssl'],
1273 ['ASN1_STRING_get0_data'],
1277 # OpenSSL versions before 1.1.0 required setting callback functions, for
1278 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1279 # function was removed.
1282 # Function introduced in OpenSSL 1.1.1
1283 ['X509_get_signature_info'],
1286 are_openssl_funcs_complete = true
1287 foreach c : check_funcs
1289 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1290 required = c.get(1, {}).get('required', false)
1291 if required and not val
1292 are_openssl_funcs_complete = false
1294 error('openssl function @0@ is required'.format(func))
1298 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1302 if are_openssl_funcs_complete
1303 cdata.set('USE_OPENSSL', 1,
1304 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1305 cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1306 description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1307 ssl_library = 'openssl'
1314 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1315 error('no SSL library found')
1320 ###############################################################
1322 ###############################################################
1324 uuidopt = get_option('uuid')
1325 if uuidopt != 'none'
1326 uuidname = uuidopt.to_upper()
1327 if uuidopt == 'e2fs'
1328 uuid = dependency('uuid', required: true)
1329 uuidfunc = 'uuid_generate'
1330 uuidheader = 'uuid/uuid.h'
1331 elif uuidopt == 'bsd'
1332 # libc should have uuid function
1333 uuid = declare_dependency()
1334 uuidfunc = 'uuid_to_string'
1335 uuidheader = 'uuid.h'
1336 elif uuidopt == 'ossp'
1337 uuid = dependency('ossp-uuid', required: true)
1338 uuidfunc = 'uuid_export'
1339 uuidheader = 'uuid.h'
1344 if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1345 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1347 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1349 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1350 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1352 uuid = not_found_dep
1357 ###############################################################
1359 ###############################################################
1361 zlibopt = get_option('zlib')
1362 zlib = not_found_dep
1363 if not zlibopt.disabled()
1364 zlib_t = dependency('zlib', required: zlibopt)
1366 if zlib_t.type_name() == 'internal'
1367 # if fallback was used, we don't need to test if headers are present (they
1368 # aren't built yet, so we can't test)
1370 elif not zlib_t.found()
1371 warning('did not find zlib')
1372 elif not cc.has_header('zlib.h',
1373 args: test_c_args, include_directories: postgres_inc,
1374 dependencies: [zlib_t], required: zlibopt.enabled())
1375 warning('zlib header not found')
1376 elif not cc.has_type('z_streamp',
1377 dependencies: [zlib_t], prefix: '#include <zlib.h>',
1378 args: test_c_args, include_directories: postgres_inc)
1379 if zlibopt.enabled()
1380 error('zlib version is too old')
1382 warning('zlib version is too old')
1389 cdata.set('HAVE_LIBZ', 1)
1395 ###############################################################
1396 # Library: tap test dependencies
1397 ###############################################################
1399 # Check whether tap tests are enabled or not
1400 tap_tests_enabled = false
1401 tapopt = get_option('tap_tests')
1402 if not tapopt.disabled()
1403 # Checking for perl modules for tap tests
1404 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1405 if perl_ipc_run_check.returncode() != 0
1406 message(perl_ipc_run_check.stderr().strip())
1408 error('Additional Perl modules are required to run TAP tests.')
1410 warning('Additional Perl modules are required to run TAP tests.')
1413 tap_tests_enabled = true
1419 ###############################################################
1421 ###############################################################
1423 zstdopt = get_option('zstd')
1424 if not zstdopt.disabled()
1425 zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1428 cdata.set('USE_ZSTD', 1)
1429 cdata.set('HAVE_LIBZSTD', 1)
1433 zstd = not_found_dep
1438 ###############################################################
1440 ###############################################################
1442 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1443 # unnecessarily, because we optionally rely on newer features.
1445 #include <stdbool.h>
1446 #include <complex.h>
1448 #include <inttypes.h>
1450 struct named_init_test {
1455 extern void structfunc(struct named_init_test);
1457 int main(int argc, char **argv)
1459 struct named_init_test nit = {
1464 for (int loop_var = 0; loop_var < 3; loop_var++)
1469 structfunc((struct named_init_test){1, 0});
1475 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1476 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1477 args: test_c_args + ['-std=c99'])
1478 test_c_args += '-std=c99'
1479 cflags += '-std=c99'
1481 error('C compiler does not support C99')
1485 sizeof_long = cc.sizeof('long', args: test_c_args)
1486 cdata.set('SIZEOF_LONG', sizeof_long)
1488 cdata.set('HAVE_LONG_INT_64', 1)
1489 cdata.set('PG_INT64_TYPE', 'long int')
1490 cdata.set_quoted('INT64_MODIFIER', 'l')
1491 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1492 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1493 cdata.set('PG_INT64_TYPE', 'long long int')
1494 cdata.set_quoted('INT64_MODIFIER', 'll')
1496 error('do not know how to get a 64bit int')
1499 if host_machine.endian() == 'big'
1500 cdata.set('WORDS_BIGENDIAN', 1)
1503 alignof_types = ['short', 'int', 'long', 'double']
1505 foreach t : alignof_types
1506 align = cc.alignment(t, args: test_c_args)
1510 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1512 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1514 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1515 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1518 # Check if __int128 is a working 128 bit integer type, and if so
1519 # define PG_INT128_TYPE to that typename.
1521 # This currently only detects a GCC/clang extension, but support for other
1522 # environments may be added in the future.
1524 # For the moment we only test for support for 128bit math; support for
1525 # 128bit literals and snprintf is not required.
1528 * We don't actually run this test, just link it to verify that any support
1529 * functions needed for __int128 are present.
1531 * These are globals to discourage the compiler from folding all the
1532 * arithmetic tests down to compile-time constants. We do not have
1533 * convenient support for 128bit literals at this point...
1535 __int128 a = 48828125;
1536 __int128 b = 97656250;
1541 a = (a << 12) + 1; /* 200000000001 */
1542 b = (b << 12) + 5; /* 400000000005 */
1543 /* try the most relevant arithmetic ops */
1546 /* must use the results, else compiler may optimize arithmetic away */
1552 buggy_int128 = false
1554 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1555 # If not cross-compiling, we can test for bugs and disable use of __int128
1556 # with buggy compilers. If cross-compiling, hope for the best.
1557 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1558 if not meson.is_cross_build()
1560 /* This must match the corresponding code in c.h: */
1561 #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1562 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1563 #elif defined(_MSC_VER)
1564 #define pg_attribute_aligned(a) __declspec(align(a))
1566 typedef __int128 int128a
1567 #if defined(pg_attribute_aligned)
1568 pg_attribute_aligned(8)
1573 void pass_by_val(void *buffer, int128a par) { holder = par; }
1577 long int i64 = 97656225L << 12;
1579 pass_by_val(main, (int128a) i64);
1583 name: '__int128 alignment bug',
1585 assert(r.compiled())
1586 if r.returncode() != 0
1588 message('__int128 support present but buggy and thus disabled')
1593 cdata.set('PG_INT128_TYPE', '__int128')
1594 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1595 alignment('__int128', args: test_c_args))
1600 # Check if the C compiler knows computed gotos (gcc extension, also
1601 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1603 # Checking whether computed gotos are supported syntax-wise ought to
1604 # be enough, as the syntax is otherwise illegal.
1606 static inline int foo(void)
1608 void *labeladdrs[] = {&&my_label};
1609 goto *labeladdrs[0];
1614 cdata.set('HAVE_COMPUTED_GOTO', 1)
1618 # Check if the C compiler understands _Static_assert(),
1619 # and define HAVE__STATIC_ASSERT if so.
1621 # We actually check the syntax ({ _Static_assert(...) }), because we need
1622 # gcc-style compound expressions to be able to wrap the thing into macros.
1624 int main(int arg, char **argv)
1626 ({ _Static_assert(1, "foo"); });
1630 cdata.set('HAVE__STATIC_ASSERT', 1)
1634 # We use <stdbool.h> if we have it and it declares type bool as having
1635 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1636 if cc.has_type('_Bool', args: test_c_args) \
1637 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1638 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1639 cdata.set('HAVE__BOOL', 1)
1640 cdata.set('PG_USE_STDBOOL', 1)
1644 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1645 # warning for each use of %m.
1646 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1648 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1649 static void call_log(void)
1651 emit_log(0, "error: %s: %m", "foo");
1654 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1655 foreach a : printf_attributes
1656 if cc.compiles(testsrc.format(a),
1657 args: test_c_args + attrib_error_args, name: 'format ' + a)
1658 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1664 if cc.has_function_attribute('visibility:default') and \
1665 cc.has_function_attribute('visibility:hidden')
1666 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1668 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1669 # inlineshidden to C code as well... Any either way, we want to put these
1670 # flags into exported files (pgxs, .pc files).
1671 cflags_mod += '-fvisibility=hidden'
1672 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1673 ldflags_mod += '-fvisibility=hidden'
1677 # Check if various builtins exist. Some builtins are tested separately,
1678 # because we want to test something more complicated than the generic case.
1691 foreach builtin : builtins
1692 fname = '__builtin_@0@'.format(builtin)
1693 if cc.has_function(fname, args: test_c_args)
1694 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1699 # Check if the C compiler understands __builtin_types_compatible_p,
1700 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1702 # We check usage with __typeof__, though it's unlikely any compiler would
1703 # have the former and not the latter.
1706 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1708 name: '__builtin_types_compatible_p',
1710 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1714 # Check if the C compiler understands __builtin_$op_overflow(),
1715 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1717 # Check for the most complicated case, 64 bit multiplication, as a
1718 # proxy for all of the operations. To detect the case where the compiler
1719 # knows the function but library support is missing, we must link not just
1720 # compile, and store the results in global variables so the compiler doesn't
1721 # optimize away the call.
1729 return __builtin_mul_overflow(a, b, &result);
1731 name: '__builtin_mul_overflow',
1732 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1734 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1738 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1739 # here. To prevent problems due to two detection methods working, stop
1740 # checking after one.
1743 int main(int arg, char **argv)
1745 unsigned int exx[4] = {0, 0, 0, 0};
1746 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1748 ''', name: '__get_cpuid',
1750 cdata.set('HAVE__GET_CPUID', 1)
1753 int main(int arg, char **argv)
1755 unsigned int exx[4] = {0, 0, 0, 0};
1758 ''', name: '__cpuid',
1760 cdata.set('HAVE__CPUID', 1)
1764 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1765 # versions of clang do not understand -fexcess-precision=standard, the use of
1766 # x87 floating point operations leads to problems like isinf possibly returning
1767 # false for a value that is infinite when converted from the 80bit register to
1768 # the 8byte memory representation.
1770 # Only perform the test if the compiler doesn't understand
1771 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1773 if '-fexcess-precision=standard' not in cflags
1774 if not cc.compiles('''
1775 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1778 name: '', args: test_c_args)
1779 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1785 ###############################################################
1787 ###############################################################
1789 common_functional_flags = [
1790 # Disable strict-aliasing rules; needed for gcc 3.3+
1791 '-fno-strict-aliasing',
1792 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1794 '-fexcess-precision=standard',
1797 cflags += cc.get_supported_arguments(common_functional_flags)
1799 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1802 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1803 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1805 common_warning_flags = [
1806 '-Wmissing-prototypes',
1808 # Really don't want VLAs to be used in our dialect of C
1810 # On macOS, complain about usage of symbols newer than the deployment target
1811 '-Werror=unguarded-availability-new',
1813 '-Wmissing-format-attribute',
1814 '-Wimplicit-fallthrough=3',
1815 '-Wcast-function-type',
1816 '-Wshadow=compatible-local',
1817 # This was included in -Wall/-Wformat in older GCC versions
1818 '-Wformat-security',
1821 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1823 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1826 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1827 # the result for them
1828 cflags_no_decl_after_statement = []
1829 if cc.has_argument('-Wdeclaration-after-statement')
1830 cflags_warn += '-Wdeclaration-after-statement'
1831 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1835 # The following tests want to suppress various unhelpful warnings by adding
1836 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1837 # switches, so we have to test for the positive form and if that works,
1838 # add the negative form.
1840 negative_warning_flags = [
1841 # Suppress clang's unhelpful unused-command-line-argument warnings.
1842 'unused-command-line-argument',
1844 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1845 # of warnings when building plperl because of usages in the Perl headers.
1846 'compound-token-split-by-macro',
1848 # Similarly disable useless truncation warnings from gcc 8+
1849 'format-truncation',
1850 'stringop-truncation',
1852 # Suppress clang 16's strict warnings about function casts
1853 'cast-function-type-strict',
1855 # To make warning_level=2 / -Wextra work, we'd need at least the following
1857 # 'missing-field-initializers',
1859 # 'unused-parameter',
1862 foreach w : negative_warning_flags
1863 if cc.has_argument('-W' + w)
1864 cflags_warn += '-Wno-' + w
1866 if llvm.found() and cpp.has_argument('-W' + w)
1867 cxxflags_warn += '-Wno-' + w
1873 if cc.get_id() == 'msvc'
1875 '/wd4018', # signed/unsigned mismatch
1876 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1877 '/wd4273', # inconsistent DLL linkage
1878 '/wd4101', # unreferenced local variable
1879 '/wd4102', # unreferenced label
1880 '/wd4090', # different 'modifier' qualifiers
1881 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1889 '/D_CRT_SECURE_NO_DEPRECATE',
1890 '/D_CRT_NONSTDC_NO_DEPRECATE',
1893 # We never need export libraries. As link.exe reports their creation, they
1894 # are unnecessarily noisy. Similarly, we don't need import library for
1895 # modules, we only import them dynamically, and they're also noisy.
1897 ldflags_mod += '/NOIMPLIB'
1902 ###############################################################
1904 ###############################################################
1906 if not get_option('spinlocks')
1907 warning('Not using spinlocks will cause poor performance')
1909 cdata.set('HAVE_SPINLOCKS', 1)
1912 if not get_option('atomics')
1913 warning('Not using atomics will cause poor performance')
1915 # XXX: perhaps we should require some atomics support in this case these
1917 cdata.set('HAVE_ATOMICS', 1)
1920 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1921 'desc': '__sync_lock_test_and_set(char)',
1924 __sync_lock_test_and_set(&lock, 1);
1925 __sync_lock_release(&lock);'''},
1927 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1928 'desc': '__sync_lock_test_and_set(int32)',
1931 __sync_lock_test_and_set(&lock, 1);
1932 __sync_lock_release(&lock);'''},
1934 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1935 'desc': '__sync_val_compare_and_swap(int32)',
1938 __sync_val_compare_and_swap(&val, 0, 37);'''},
1940 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1941 'desc': '__sync_val_compare_and_swap(int64)',
1944 __sync_val_compare_and_swap(&val, 0, 37);'''},
1946 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1947 'desc': ' __atomic_compare_exchange_n(int32)',
1951 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1953 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1954 'desc': ' __atomic_compare_exchange_n(int64)',
1958 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1961 foreach check : atomic_checks
1966 }'''.format(check['test'])
1968 cdata.set(check['name'],
1970 name: check['desc'],
1971 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1979 ###############################################################
1980 # Select CRC-32C implementation.
1982 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1983 # use the special CRC instructions for calculating CRC-32C. If we're not
1984 # targeting such a processor, but we can nevertheless produce code that uses
1985 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1986 # implementations and select which one to use at runtime, depending on whether
1987 # SSE 4.2 is supported by the processor we're running on.
1989 # Similarly, if we are targeting an ARM processor that has the CRC
1990 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1991 # we're not targeting such a processor, but can nevertheless produce code that
1992 # uses the CRC instructions, compile both, and select at runtime.
1993 ###############################################################
1995 have_optimized_crc = false
1997 if host_cpu == 'x86' or host_cpu == 'x86_64'
1999 if cc.get_id() == 'msvc'
2000 cdata.set('USE_SSE42_CRC32C', false)
2001 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2002 have_optimized_crc = true
2006 #include <nmmintrin.h>
2010 unsigned int crc = 0;
2011 crc = _mm_crc32_u8(crc, 0);
2012 crc = _mm_crc32_u32(crc, 0);
2013 /* return computed value, to prevent the above being optimized away */
2018 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2020 # Use Intel SSE 4.2 unconditionally.
2021 cdata.set('USE_SSE42_CRC32C', 1)
2022 have_optimized_crc = true
2023 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2024 args: test_c_args + ['-msse4.2'])
2025 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2026 # the runtime check.
2027 cflags_crc += '-msse4.2'
2028 cdata.set('USE_SSE42_CRC32C', false)
2029 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2030 have_optimized_crc = true
2035 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2038 #include <arm_acle.h>
2042 unsigned int crc = 0;
2043 crc = __crc32cb(crc, 0);
2044 crc = __crc32ch(crc, 0);
2045 crc = __crc32cw(crc, 0);
2046 crc = __crc32cd(crc, 0);
2048 /* return computed value, to prevent the above being optimized away */
2053 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2055 # Use ARM CRC Extension unconditionally
2056 cdata.set('USE_ARMV8_CRC32C', 1)
2057 have_optimized_crc = true
2058 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2059 args: test_c_args + ['-march=armv8-a+crc'])
2060 # Use ARM CRC Extension, with runtime check
2061 cflags_crc += '-march=armv8-a+crc'
2062 cdata.set('USE_ARMV8_CRC32C', false)
2063 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2064 have_optimized_crc = true
2068 if not have_optimized_crc
2069 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2071 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2076 ###############################################################
2077 # Other CPU specific stuff
2078 ###############################################################
2080 if host_cpu == 'x86_64'
2085 long long x = 1; long long r;
2086 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2088 name: '@0@: popcntq instruction'.format(host_cpu),
2090 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2093 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2094 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2095 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2098 addi(int ra, int si)
2101 if (__builtin_constant_p(si))
2102 __asm__ __volatile__(
2103 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2106 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2109 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2116 ###############################################################
2117 # Library / OS tests
2118 ###############################################################
2120 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2121 # unnecessary checks over and over, particularly on windows.
2135 'sys/personality.h',
2144 foreach header : header_checks
2145 varname = 'HAVE_' + header.underscorify().to_upper()
2147 # Emulate autoconf behaviour of not-found->undef, found->1
2148 found = cc.has_header(header,
2149 include_directories: postgres_inc, args: test_c_args)
2150 cdata.set(varname, found ? 1 : false,
2151 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2156 ['F_FULLFSYNC', 'fcntl.h'],
2157 ['fdatasync', 'unistd.h'],
2158 ['posix_fadvise', 'fcntl.h'],
2159 ['strlcat', 'string.h'],
2160 ['strlcpy', 'string.h'],
2161 ['strnlen', 'string.h'],
2164 # Need to check for function declarations for these functions, because
2165 # checking for library symbols wouldn't handle deployment target
2166 # restrictions on macOS
2168 ['preadv', 'sys/uio.h'],
2169 ['pwritev', 'sys/uio.h'],
2172 foreach c : decl_checks
2176 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2178 found = cc.has_header_symbol(header, func,
2179 args: test_c_args, include_directories: postgres_inc,
2181 cdata.set10(varname, found, description:
2182 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2183 don't.'''.format(func))
2187 if cc.has_type('struct option',
2188 args: test_c_args, include_directories: postgres_inc,
2189 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2190 cdata.set('HAVE_STRUCT_OPTION', 1)
2194 foreach c : ['opterr', 'optreset']
2195 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2204 '''.format(c), name: c, args: test_c_args)
2205 cdata.set(varname, 1)
2207 cdata.set(varname, false)
2211 if cc.has_type('socklen_t',
2212 args: test_c_args, include_directories: postgres_inc,
2214 #include <sys/socket.h>''')
2215 cdata.set('HAVE_SOCKLEN_T', 1)
2218 if cc.has_member('struct sockaddr', 'sa_len',
2219 args: test_c_args, include_directories: postgres_inc,
2221 #include <sys/types.h>
2222 #include <sys/socket.h>''')
2223 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2226 if cc.has_member('struct tm', 'tm_zone',
2227 args: test_c_args, include_directories: postgres_inc,
2229 #include <sys/types.h>
2232 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2237 extern int foo(void);
2240 return timezone / 60;
2243 name: 'global variable `timezone\' exists',
2244 args: test_c_args, include_directories: postgres_inc)
2245 cdata.set('HAVE_INT_TIMEZONE', 1)
2247 cdata.set('HAVE_INT_TIMEZONE', false)
2250 if cc.has_type('union semun',
2252 include_directories: postgres_inc,
2254 #include <sys/types.h>
2255 #include <sys/ipc.h>
2256 #include <sys/sem.h>
2258 cdata.set('HAVE_UNION_SEMUN', 1)
2266 switch (strerror_r(1, buf, sizeof(buf)))
2267 { case 0: break; default: break; }
2270 args: test_c_args, include_directories: postgres_inc)
2271 cdata.set('STRERROR_R_INT', 1)
2273 cdata.set('STRERROR_R_INT', false)
2276 # Check for the locale_t type and find the right header file. macOS
2277 # needs xlocale.h; standard is locale.h, but glibc also has an
2278 # xlocale.h file that we should not use. MSVC has a replacement
2279 # defined in src/include/port/win32_port.h.
2280 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2281 cdata.set('HAVE_LOCALE_T', 1)
2282 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2283 cdata.set('HAVE_LOCALE_T', 1)
2284 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2285 elif cc.get_id() == 'msvc'
2286 cdata.set('HAVE_LOCALE_T', 1)
2289 # Check if the C compiler understands typeof or a variant. Define
2290 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2291 foreach kw : ['typeof', '__typeof__', 'decltype']
2302 args: test_c_args, include_directories: postgres_inc)
2304 cdata.set('HAVE_TYPEOF', 1)
2306 cdata.set('typeof', kw)
2314 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2315 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2316 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2317 wcstombs_l_test = '''
2329 if (not cc.compiles(wcstombs_l_test.format(''),
2330 name: 'wcstombs_l') and
2331 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2332 name: 'wcstombs_l in xlocale.h'))
2333 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2337 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2338 # understands, because it conflicts with __declspec(restrict). Therefore we
2339 # define pg_restrict to the appropriate definition, which presumably won't
2342 # We assume C99 support, so we don't need to make this conditional.
2344 # XXX: Historically we allowed platforms to disable restrict in template
2345 # files, but that was only added for AIX when building with XLC, which we
2346 # don't support yet.
2347 cdata.set('pg_restrict', '__restrict')
2350 # Most libraries are included only if they demonstrably provide a function we
2351 # need, but libm is an exception: always include it, because there are too
2352 # many compilers that play cute optimization games that will break probes for
2353 # standard functions such as pow().
2354 os_deps += cc.find_library('m', required: false)
2356 rt_dep = cc.find_library('rt', required: false)
2358 dl_dep = cc.find_library('dl', required: false)
2360 util_dep = cc.find_library('util', required: false)
2361 posix4_dep = cc.find_library('posix4', required: false)
2363 getopt_dep = cc.find_library('getopt', required: false)
2364 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2365 # Check if we want to replace getopt/getopt_long even if provided by the system
2366 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2367 # so always use our version on Windows
2368 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2369 # (i.e., allow '-' as a flag character), so use our version on those platforms
2370 # - We want to use system's getopt_long() only if the system provides struct
2372 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2373 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2376 execinfo_dep = cc.find_library('execinfo', required: false)
2378 if host_system == 'cygwin'
2379 cygipc_dep = cc.find_library('cygipc', required: false)
2381 cygipc_dep = not_found_dep
2384 if host_system == 'sunos'
2385 socket_dep = cc.find_library('socket', required: false)
2387 socket_dep = not_found_dep
2390 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2391 # unnecessary checks over and over, particularly on windows.
2393 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2394 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2395 ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2397 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2398 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2399 # required. Just checking for dlsym() ought to suffice.
2400 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2402 ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2404 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2405 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2415 ['posix_fallocate'],
2418 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2419 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2420 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2421 ['setproctitle', {'dependencies': [util_dep]}],
2422 ['setproctitle_fast'],
2423 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2424 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2425 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2426 ['socket', {'dependencies': [socket_dep], 'define': false}],
2428 ['strerror_r', {'dependencies': [thread_dep]}],
2433 ['sync_file_range'],
2439 func_check_results = {}
2440 foreach c : func_checks
2442 kwargs = c.get(1, {})
2443 deps = kwargs.get('dependencies', [])
2445 if kwargs.get('skip', false)
2449 found = cc.has_function(func, args: test_c_args)
2456 found = cc.has_function(func, args: test_c_args,
2457 dependencies: [dep])
2465 func_check_results += {func: found}
2467 if kwargs.get('define', true)
2468 # Emulate autoconf behaviour of not-found->undef, found->1
2469 cdata.set('HAVE_' + func.underscorify().to_upper(),
2471 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2476 if cc.has_function('syslog', args: test_c_args) and \
2477 cc.check_header('syslog.h', args: test_c_args)
2478 cdata.set('HAVE_SYSLOG', 1)
2482 # MSVC has replacements defined in src/include/port/win32_port.h.
2483 if cc.get_id() == 'msvc'
2484 cdata.set('HAVE_WCSTOMBS_L', 1)
2485 cdata.set('HAVE_MBSTOWCS_L', 1)
2489 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2491 if sema_kind == 'unnamed_posix' and \
2492 not func_check_results.get('sem_init', false)
2496 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2497 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2499 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2500 cdata.set_quoted('DLSUFFIX', dlsuffix)
2503 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2504 cdata.set_quoted('PG_VERSION_STR',
2505 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2506 pg_version, host_machine.cpu_family(), host_system,
2507 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2513 ###############################################################
2515 ###############################################################
2517 # XXX: About to rely on thread safety in the autoconf build, so not worth
2518 # implementing a fallback.
2519 cdata.set('ENABLE_THREAD_SAFETY', 1)
2523 ###############################################################
2525 ###############################################################
2527 nlsopt = get_option('nls')
2528 libintl = not_found_dep
2530 if not nlsopt.disabled()
2531 # otherwise there'd be lots of
2532 # "Gettext not found, all translation (po) targets will be ignored."
2533 # warnings if not found.
2534 msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2536 # meson 0.59 has this wrapped in dependency('int')
2537 if (msgfmt.found() and
2538 cc.check_header('libintl.h', required: nlsopt,
2539 args: test_c_args, include_directories: postgres_inc))
2542 if cc.has_function('ngettext')
2543 libintl = declare_dependency()
2545 libintl = cc.find_library('intl',
2546 has_headers: ['libintl.h'], required: nlsopt,
2547 header_include_directories: postgres_inc,
2553 i18n = import('i18n')
2554 cdata.set('ENABLE_NLS', 1)
2560 ###############################################################
2562 ###############################################################
2564 # Set up compiler / linker arguments to be used everywhere, individual targets
2565 # can add further args directly, or indirectly via dependencies
2566 add_project_arguments(cflags, language: ['c'])
2567 add_project_arguments(cppflags, language: ['c'])
2568 add_project_arguments(cflags_warn, language: ['c'])
2569 add_project_arguments(cxxflags, language: ['cpp'])
2570 add_project_arguments(cppflags, language: ['cpp'])
2571 add_project_arguments(cxxflags_warn, language: ['cpp'])
2572 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2575 # Collect a number of lists of things while recursing through the source
2576 # tree. Later steps then can use those.
2578 # list of targets for various alias targets
2579 backend_targets = []
2582 contrib_targets = []
2583 testprep_targets = []
2587 # Define the tests to distribute them to the correct test styles later
2592 # Default options for targets
2594 # First identify rpaths
2595 bin_install_rpaths = []
2596 lib_install_rpaths = []
2597 mod_install_rpaths = []
2600 # Don't add rpaths on darwin for now - as long as only absolute references to
2601 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2602 # their final destination.
2603 if host_system != 'darwin'
2604 # Add absolute path to libdir to rpath. This ensures installed binaries /
2605 # libraries find our libraries (mainly libpq).
2606 bin_install_rpaths += dir_prefix / dir_lib
2607 lib_install_rpaths += dir_prefix / dir_lib
2608 mod_install_rpaths += dir_prefix / dir_lib
2610 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2612 # Not needed on darwin even if we use relative rpaths for our own libraries,
2613 # as the install_name of libraries in extra_lib_dirs will point to their
2615 bin_install_rpaths += postgres_lib_d
2616 lib_install_rpaths += postgres_lib_d
2617 mod_install_rpaths += postgres_lib_d
2621 # Define arguments for default targets
2623 default_target_args = {
2624 'implicit_include_directories': false,
2628 default_lib_args = default_target_args + {
2632 internal_lib_args = default_lib_args + {
2633 'build_by_default': false,
2637 default_mod_args = default_lib_args + {
2639 'install_dir': dir_lib_pkg,
2642 default_bin_args = default_target_args + {
2643 'install_dir': dir_bin,
2646 if get_option('rpath')
2647 default_lib_args += {
2648 'install_rpath': ':'.join(lib_install_rpaths),
2651 default_mod_args += {
2652 'install_rpath': ':'.join(mod_install_rpaths),
2655 default_bin_args += {
2656 'install_rpath': ':'.join(bin_install_rpaths),
2661 # Helper for exporting a limited number of symbols
2662 gen_export_kwargs = {
2663 'input': 'exports.txt',
2664 'output': '@BASENAME@.'+export_file_suffix,
2665 'command': [perl, files('src/tools/gen_export.pl'),
2666 '--format', export_file_format,
2667 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2668 'build_by_default': false,
2675 ### windows resources related stuff
2678 if host_system == 'windows'
2679 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2680 win32ver_rc = files('src/port/win32ver.rc')
2681 rcgen = find_program('src/tools/rcgen', native: true)
2684 '--srcdir', '@SOURCE_DIR@',
2685 '--builddir', meson.build_root(),
2686 '--rcout', '@OUTPUT0@',
2687 '--out', '@OUTPUT1@',
2688 '--input', '@INPUT@',
2692 if cc.get_argument_syntax() == 'msvc'
2693 rc = find_program('rc', required: true)
2694 rcgen_base_args += ['--rc', rc.path()]
2695 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2697 windres = find_program('windres', required: true)
2698 rcgen_base_args += ['--windres', windres.path()]
2699 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2702 # msbuild backend doesn't support this atm
2703 if meson.backend() == 'ninja'
2704 rcgen_base_args += ['--depfile', '@DEPFILE@']
2707 rcgen_bin_args = rcgen_base_args + [
2708 '--VFT_TYPE', 'VFT_APP',
2709 '--FILEENDING', 'exe',
2713 rcgen_lib_args = rcgen_base_args + [
2714 '--VFT_TYPE', 'VFT_DLL',
2715 '--FILEENDING', 'dll',
2718 rc_bin_gen = generator(rcgen,
2719 depfile: '@BASENAME@.d',
2720 arguments: rcgen_bin_args,
2721 output: rcgen_outputs,
2724 rc_lib_gen = generator(rcgen,
2725 depfile: '@BASENAME@.d',
2726 arguments: rcgen_lib_args,
2727 output: rcgen_outputs,
2733 # headers that the whole build tree depends on
2734 generated_headers = []
2735 # headers that the backend build depends on
2736 generated_backend_headers = []
2737 # configure_files() output, needs a way of converting to file names
2738 configure_files = []
2740 # generated files that might conflict with a partial in-tree autoconf build
2741 generated_sources = []
2742 # same, for paths that differ between autoconf / meson builds
2743 # elements are [dir, [files]]
2744 generated_sources_ac = {}
2747 # First visit src/include - all targets creating headers are defined
2748 # within. That makes it easy to add the necessary dependencies for the
2749 # subsequent build steps.
2751 subdir('src/include')
2755 # Then through src/port and src/common, as most other things depend on them
2757 frontend_port_code = declare_dependency(
2758 compile_args: ['-DFRONTEND'],
2759 include_directories: [postgres_inc],
2760 dependencies: os_deps,
2763 backend_port_code = declare_dependency(
2764 compile_args: ['-DBUILDING_DLL'],
2765 include_directories: [postgres_inc],
2766 sources: [errcodes], # errcodes.h is needed due to use of ereport
2767 dependencies: os_deps,
2772 frontend_common_code = declare_dependency(
2773 compile_args: ['-DFRONTEND'],
2774 include_directories: [postgres_inc],
2775 sources: generated_headers,
2776 dependencies: [os_deps, zlib, zstd],
2779 backend_common_code = declare_dependency(
2780 compile_args: ['-DBUILDING_DLL'],
2781 include_directories: [postgres_inc],
2782 sources: generated_headers,
2783 dependencies: [os_deps, zlib, zstd],
2786 subdir('src/common')
2788 # all shared libraries should depend on shlib_code
2789 shlib_code = declare_dependency(
2790 link_args: ldflags_sl,
2793 # all static libraries not part of the backend should depend on this
2794 frontend_stlib_code = declare_dependency(
2795 include_directories: [postgres_inc],
2796 link_with: [common_static, pgport_static],
2797 sources: generated_headers,
2798 dependencies: [os_deps, libintl],
2801 # all shared libraries not part of the backend should depend on this
2802 frontend_shlib_code = declare_dependency(
2803 include_directories: [postgres_inc],
2804 link_with: [common_shlib, pgport_shlib],
2805 sources: generated_headers,
2806 dependencies: [shlib_code, os_deps, libintl],
2809 # Dependencies both for static and shared libpq
2819 subdir('src/interfaces/libpq')
2820 # fe_utils depends on libpq
2821 subdir('src/fe_utils')
2823 # for frontend binaries
2824 frontend_code = declare_dependency(
2825 include_directories: [postgres_inc],
2826 link_with: [fe_utils, common_static, pgport_static],
2827 sources: generated_headers,
2828 dependencies: [os_deps, libintl],
2831 backend_both_deps += [
2848 backend_mod_deps = backend_both_deps + os_deps
2850 backend_code = declare_dependency(
2851 compile_args: ['-DBUILDING_DLL'],
2852 include_directories: [postgres_inc],
2853 link_args: ldflags_be,
2855 sources: generated_headers + generated_backend_headers,
2856 dependencies: os_deps + backend_both_deps + backend_deps,
2859 # install these files only during test, not main install
2860 test_install_data = []
2861 test_install_libs = []
2863 # src/backend/meson.build defines backend_mod_code used for extension
2867 # Then through the main sources. That way contrib can have dependencies on
2868 # main sources. Note that this explicitly doesn't enter src/test, right now a
2869 # few regression tests depend on contrib files.
2876 subdir('src/interfaces/libpq/test')
2877 subdir('src/interfaces/ecpg/test')
2879 subdir('doc/src/sgml')
2881 generated_sources_ac += {'': ['GNUmakefile']}
2883 # After processing src/test, add test_install_libs to the testprep_targets
2885 testprep_targets += test_install_libs
2888 # If there are any files in the source directory that we also generate in the
2889 # build directory, they might get preferred over the newly generated files,
2890 # e.g. because of a #include "file", which always will search in the current
2892 message('checking for file conflicts between source and build directory')
2893 conflicting_files = []
2894 potentially_conflicting_files_t = []
2895 potentially_conflicting_files_t += generated_headers
2896 potentially_conflicting_files_t += generated_backend_headers
2897 potentially_conflicting_files_t += generated_backend_sources
2898 potentially_conflicting_files_t += generated_sources
2900 potentially_conflicting_files = []
2902 # convert all sources of potentially conflicting files into uniform shape
2903 foreach t : potentially_conflicting_files_t
2904 potentially_conflicting_files += t.full_path()
2906 foreach t : configure_files
2908 potentially_conflicting_files += meson.current_build_dir() / t
2910 foreach sub, fnames : generated_sources_ac
2911 sub = meson.build_root() / sub
2912 foreach fname : fnames
2913 potentially_conflicting_files += sub / fname
2917 # find and report conflicting files
2918 foreach build_path : potentially_conflicting_files
2919 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2920 # str.replace is in 0.56
2921 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2922 if fs.exists(src_path) or fs.is_symlink(src_path)
2923 conflicting_files += src_path
2926 # XXX: Perhaps we should generate a file that would clean these up? The list
2928 if conflicting_files.length() > 0
2929 errmsg_cleanup = '''
2930 Conflicting files in source directory:
2933 The conflicting files need to be removed, either by removing the files listed
2934 above, or by running configure and then make maintainer-clean.
2936 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2937 error(errmsg_nonclean_base.format(errmsg_cleanup))
2942 ###############################################################
2944 ###############################################################
2947 # We want to define additional install targets beyond what meson provides. For
2948 # that we need to define targets depending on nearly everything. We collected
2949 # the results of i18n.gettext() invocations into nls_targets, that also
2950 # includes maintainer targets though. Collect the ones we want as a dependency.
2952 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
2953 # generation happens during install, so that's not a real issue.
2955 if libintl.found() and meson.version().version_compare('>=0.60')
2956 # use range() to avoid the flattening of the list that forech() would do
2957 foreach off : range(0, nls_targets.length())
2958 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
2959 # -pot target 3) maintainer -pot target
2960 nls_mo_targets += nls_targets[off][0]
2962 alias_target('nls', nls_mo_targets)
2977 # Meson's default install target is quite verbose. Provide one that is quiet.
2978 install_quiet = custom_target('install-quiet',
2979 output: 'install-quiet',
2980 build_always_stale: true,
2981 build_by_default: false,
2982 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
2986 # Target to install files used for tests, which aren't installed by default
2987 install_test_files_args = [
2989 '--prefix', dir_prefix,
2990 '--install', contrib_data_dir, test_install_data,
2991 '--install', dir_lib_pkg, test_install_libs,
2993 run_target('install-test-files',
2994 command: [python] + install_test_files_args,
2995 depends: testprep_targets,
3000 ###############################################################
3002 ###############################################################
3004 # DESTDIR for the installation we'll run tests in
3005 test_install_destdir = meson.build_root() / 'tmp_install/'
3007 # DESTDIR + prefix appropriately munged
3008 if build_system != 'windows'
3009 # On unixoid systems this is trivial, we just prepend the destdir
3010 assert(dir_prefix.startswith('/')) # enforced by meson
3011 test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3013 # drives, drive-relative paths, etc make this complicated on windows, call
3014 # into a copy of meson's logic for it
3017 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3018 test_install_destdir, dir_prefix]
3019 test_install_location = run_command(command, check: true).stdout().strip()
3022 meson_install_args = meson_args + ['install'] + {
3023 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3027 # setup tests should be run first,
3028 # so define priority for these
3029 setup_tests_priority = 100
3031 meson_bin, args: meson_install_args ,
3032 env: {'DESTDIR':test_install_destdir},
3033 priority: setup_tests_priority,
3038 test('install_test_files',
3040 args: install_test_files_args + ['--destdir', test_install_destdir],
3041 priority: setup_tests_priority,
3045 test_result_dir = meson.build_root() / 'testrun'
3048 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3049 # inevitable conflicts from running tests in parallel, hackishly assign
3050 # different ports for different tests.
3054 test_env = environment()
3056 temp_install_bindir = test_install_location / get_option('bindir')
3057 test_env.set('PG_REGRESS', pg_regress.full_path())
3058 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3060 # Test suites that are not safe by default but can be run if selected
3061 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3062 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3063 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3065 # Add the temporary installation to the library search path on platforms where
3066 # that works (everything but windows, basically). On windows everything
3067 # library-like gets installed into bindir, solving that issue.
3068 if library_path_var != ''
3069 test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3074 ###############################################################
3076 ###############################################################
3078 # When using a meson version understanding exclude_suites, define a
3079 # 'tmp_install' test setup (the default) that excludes tests running against a
3080 # pre-existing install and a 'running' setup that conflicts with creation of
3081 # the temporary installation and tap tests (which don't support running
3082 # against a running server).
3086 if meson.version().version_compare('>=0.57')
3089 runningcheck = false
3092 testwrap = files('src/tools/testwrap')
3094 foreach test_dir : tests
3097 '--basedir', meson.build_root(),
3098 '--srcdir', test_dir['sd'],
3101 foreach kind, v : test_dir
3102 if kind in ['sd', 'bd', 'name']
3108 if kind in ['regress', 'isolation', 'ecpg']
3109 if kind == 'regress'
3111 fallback_dbname = 'regression_@0@'
3112 elif kind == 'isolation'
3113 runner = pg_isolation_regress
3114 fallback_dbname = 'isolation_regression_@0@'
3116 runner = pg_regress_ecpg
3117 fallback_dbname = 'ecpg_regression_@0@'
3120 test_group = test_dir['name']
3121 test_group_running = test_dir['name'] + '-running'
3123 test_output = test_result_dir / test_group / kind
3124 test_output_running = test_result_dir / test_group_running/ kind
3126 # Unless specified by the test, choose a non-conflicting database name,
3127 # to avoid conflicts when running against existing server.
3128 dbname = t.get('dbname',
3129 fallback_dbname.format(test_dir['name']))
3131 test_command_base = [
3133 '--inputdir', t.get('inputdir', test_dir['sd']),
3134 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3136 '--dlpath', test_dir['bd'],
3137 '--max-concurrent-tests=20',
3139 ] + t.get('regress_args', [])
3142 if t.has_key('schedule')
3143 test_selection += ['--schedule', t['schedule'],]
3146 if kind == 'isolation'
3147 test_selection += t.get('specs', [])
3149 test_selection += t.get('sql', [])
3153 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3159 'depends': test_deps + t.get('deps', []),
3161 } + t.get('test_kwargs', {})
3163 test(test_group / kind,
3167 '--testgroup', test_group,
3171 '--outputdir', test_output,
3172 '--temp-instance', test_output / 'tmp_check',
3173 '--port', testport.to_string(),
3177 kwargs: test_kwargs,
3179 install_suites += test_group
3181 # some tests can't support running against running DB
3182 if runningcheck and t.get('runningcheck', true)
3183 test(test_group_running / kind,
3187 '--testgroup', test_group_running,
3191 '--outputdir', test_output_running,
3194 is_parallel: t.get('runningcheck-parallel', true),
3195 suite: test_group_running,
3196 kwargs: test_kwargs,
3198 running_suites += test_group_running
3203 if not tap_tests_enabled
3209 '-I', meson.source_root() / 'src/test/perl',
3210 '-I', test_dir['sd'],
3213 # Add temporary install, the build directory for non-installed binaries and
3214 # also test/ for non-installed test binaries built separately.
3216 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3218 foreach name, value : t.get('env', {})
3219 env.set(name, value)
3222 test_group = test_dir['name']
3225 'suite': test_group,
3227 'depends': test_deps + t.get('deps', []),
3229 } + t.get('test_kwargs', {})
3231 foreach onetap : t['tests']
3232 # Make tap test names prettier, remove t/ and .pl
3234 if onetap_p.startswith('t/')
3235 onetap_p = onetap.split('t/')[1]
3237 if onetap_p.endswith('.pl')
3238 onetap_p = fs.stem(onetap_p)
3241 test(test_dir['name'] / onetap_p,
3243 kwargs: test_kwargs,
3244 args: testwrap_base + [
3245 '--testgroup', test_dir['name'],
3246 '--testname', onetap_p,
3248 test_dir['sd'] / onetap,
3252 install_suites += test_group
3254 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3257 endforeach # kinds of tests
3259 endforeach # directories with tests
3261 # repeat condition so meson realizes version dependency
3262 if meson.version().version_compare('>=0.57')
3263 add_test_setup('tmp_install',
3265 exclude_suites: running_suites)
3266 add_test_setup('running',
3267 exclude_suites: ['setup'] + install_suites)
3272 ###############################################################
3274 ###############################################################
3276 alias_target('backend', backend_targets)
3277 alias_target('bin', bin_targets + [libpq_st])
3278 alias_target('pl', pl_targets)
3279 alias_target('contrib', contrib_targets)
3280 alias_target('testprep', testprep_targets)
3281 alias_target('install-world', install_quiet, installdocs)
3285 ###############################################################
3286 # The End, The End, My Friend
3287 ###############################################################
3289 if meson.version().version_compare('>=0.57')
3293 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3294 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3295 'segment size': get_option('segsize_blocks') != 0 ?
3296 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3297 '@0@ GB'.format(get_option('segsize')),
3299 section: 'Data layout',
3304 'host system': '@0@ @1@'.format(host_system, host_cpu),
3305 'build system': '@0@ @1@'.format(build_machine.system(),
3306 build_machine.cpu_family()),
3313 'linker': '@0@'.format(cc.get_linker_id()),
3314 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3316 section: 'Compiler',
3321 'CPP FLAGS': ' '.join(cppflags),
3322 'C FLAGS, functional': ' '.join(cflags),
3323 'C FLAGS, warnings': ' '.join(cflags_warn),
3324 'C FLAGS, modules': ' '.join(cflags_mod),
3325 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3326 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3328 section: 'Compiler Flags',
3334 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3336 section: 'Compiler',
3341 'C++ FLAGS, functional': ' '.join(cxxflags),
3342 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3343 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3345 section: 'Compiler Flags',
3351 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3354 section: 'Programs',
3360 'bsd_auth': bsd_auth,
3362 'docs_pdf': docs_pdf_dep,
3374 'plpython': python3_dep,
3376 'readline': readline,
3383 section: 'External libraries',