1 # Entry point for building PostgreSQL with meson
3 # Good starting points for writing meson.build files are:
4 # - https://mesonbuild.com/Syntax.html
5 # - https://mesonbuild.com/Reference-manual.html
10 license: 'PostgreSQL',
12 # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
13 # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
14 # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
15 meson_version: '>=0.54',
17 'warning_level=1', #-Wall equivalent
20 # For compatibility with the autoconf build, set a default prefix. This
21 # works even on windows, where it's a drive-relative path (i.e. when on
22 # d:/sompath it'll install to d:/usr/local/pgsql)
23 'prefix=/usr/local/pgsql',
29 ###############################################################
31 ###############################################################
34 pkgconfig = import('pkgconfig')
36 host_system = host_machine.system()
37 build_system = build_machine.system()
38 host_cpu = host_machine.cpu_family()
40 cc = meson.get_compiler('c')
42 not_found_dep = dependency('', required: false)
43 thread_dep = dependency('threads')
47 ###############################################################
49 ###############################################################
51 # It's very easy to get into confusing states when the source directory
52 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
53 # refuse to build in that case.
55 # There's a more elaborate check later, that checks for conflicts around all
56 # generated files. But we can only do that much further down the line, so this
57 # quick check seems worth it. Adhering to this advice should clean up the
58 # conflict, but won't protect against somebody doing make distclean or just
59 # removing pg_config.h
60 errmsg_nonclean_base = '''
62 Non-clean source code directory detected.
64 To build with meson the source tree may not have an in-place, ./configure
65 style, build configured. You can have both meson and ./configure style builds
66 for the same source tree by building out-of-source / VPATH with
67 configure. Alternatively use a separate check out for meson based builds.
71 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
72 errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
73 error(errmsg_nonclean_base.format(errmsg_cleanup))
78 ###############################################################
79 # Variables to be determined
80 ###############################################################
82 postgres_inc_d = ['src/include']
83 postgres_inc_d += get_option('extra_include_dirs')
85 postgres_lib_d = get_option('extra_lib_dirs')
104 backend_both_deps = []
110 # source of data for pg_config.h etc
111 cdata = configuration_data()
115 ###############################################################
116 # Version and other metadata
117 ###############################################################
119 pg_version = meson.project_version()
121 if pg_version.endswith('devel')
122 pg_version_arr = [pg_version.split('devel')[0], '0']
123 elif pg_version.contains('beta')
124 pg_version_arr = [pg_version.split('beta')[0], '0']
125 elif pg_version.contains('rc')
126 pg_version_arr = [pg_version.split('rc')[0], '0']
128 pg_version_arr = pg_version.split('.')
131 pg_version_major = pg_version_arr[0].to_int()
132 pg_version_minor = pg_version_arr[1].to_int()
133 pg_version_num = (pg_version_major * 10000) + pg_version_minor
135 pg_url = 'https://www.postgresql.org/'
137 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
138 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
139 cdata.set_quoted('PACKAGE_URL', pg_url)
140 cdata.set_quoted('PACKAGE_VERSION', pg_version)
141 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
142 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
144 pg_version += get_option('extra_version')
145 cdata.set_quoted('PG_VERSION', pg_version)
146 cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by @2@-@3@'.format(
147 pg_version, build_machine.cpu_family(), cc.get_id(), cc.version()))
148 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
149 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
150 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
151 cdata.set('PG_VERSION_NUM', pg_version_num)
152 cdata.set_quoted('CONFIGURE_ARGS', '')
156 ###############################################################
157 # Basic platform specific configuration
158 ###############################################################
160 # meson's system names don't quite map to our "traditional" names. In some
161 # places we need the "traditional" name, e.g., for mapping
162 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
164 portname = host_system
166 exesuffix = '' # overridden below where necessary
167 dlsuffix = '.so' # overridden below where necessary
168 library_path_var = 'LD_LIBRARY_PATH'
170 # Format of file to control exports from libraries, and how to pass them to
171 # the compiler. For export_fmt @0@ is the path to the file export file.
172 export_file_format = 'gnu'
173 export_file_suffix = 'list'
174 export_fmt = '-Wl,--version-script=@0@'
176 # Flags to add when linking a postgres extension, @0@ is path to
177 # the relevant object on the platform.
178 mod_link_args_fmt = []
180 memset_loop_limit = 1024
182 # Choice of shared memory and semaphore implementation
186 # We implement support for some operating systems by pretending they're
187 # another. Map here, before determining system properties below
188 if host_system == 'dragonfly'
189 # apparently the most similar
190 host_system = 'netbsd'
193 if host_system == 'aix'
194 library_path_var = 'LIBPATH'
196 export_file_format = 'aix'
197 export_fmt = '-Wl,-bE:@0@'
198 mod_link_args_fmt = ['-Wl,-bI:@0@']
199 mod_link_with_dir = 'libdir'
200 mod_link_with_name = '@0@.imp'
202 # M:SRE sets a flag indicating that an object is a shared library. Seems to
203 # work in some circumstances without, but required in others.
204 ldflags_sl += '-Wl,-bM:SRE'
205 ldflags_be += '-Wl,-brtllib'
207 # Native memset() is faster, tested on:
208 # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
209 # - AIX 5.3 ML3, gcc 4.0.1
210 memset_loop_limit = 0
212 elif host_system == 'cygwin'
213 cppflags += '-D_GNU_SOURCE'
215 mod_link_args_fmt = ['@0@']
216 mod_link_with_name = 'lib@0@.exe.a'
217 mod_link_with_dir = 'libdir'
219 elif host_system == 'darwin'
221 library_path_var = 'DYLD_LIBRARY_PATH'
223 export_file_format = 'darwin'
224 export_fmt = '-exported_symbols_list=@0@'
226 mod_link_args_fmt = ['-bundle_loader', '@0@']
227 mod_link_with_dir = 'bindir'
228 mod_link_with_name = '@0@'
230 sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
231 pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
232 message('darwin sysroot: @0@'.format(pg_sysroot))
233 cflags += ['-isysroot', pg_sysroot]
234 ldflags += ['-isysroot', pg_sysroot]
235 # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
236 # don't want because a) it's different from what we do for autoconf, b) it
237 # causes warnings starting in macOS Ventura
238 ldflags_mod += ['-Wl,-undefined,error']
240 elif host_system == 'freebsd'
241 sema_kind = 'unnamed_posix'
243 elif host_system == 'linux'
244 sema_kind = 'unnamed_posix'
245 cppflags += '-D_GNU_SOURCE'
247 elif host_system == 'netbsd'
248 # We must resolve all dynamic linking in the core server at program start.
249 # Otherwise the postmaster can self-deadlock due to signals interrupting
250 # resolution of calls, since NetBSD's linker takes a lock while doing that
251 # and some postmaster signal handlers do things that will also acquire that
252 # lock. As long as we need "-z now", might as well specify "-z relro" too.
253 # While there's not a hard reason to adopt these settings for our other
254 # executables, there's also little reason not to, so just add them to
256 ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
258 elif host_system == 'openbsd'
261 elif host_system == 'sunos'
263 export_fmt = '-Wl,-M@0@'
264 cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
266 elif host_system == 'windows'
270 library_path_var = ''
272 export_file_format = 'win'
273 export_file_suffix = 'def'
274 if cc.get_id() == 'msvc'
275 export_fmt = '/DEF:@0@'
276 mod_link_with_name = '@0@.exe.lib'
279 mod_link_with_name = 'lib@0@.exe.a'
281 mod_link_args_fmt = ['@0@']
282 mod_link_with_dir = 'libdir'
287 cdata.set('WIN32_STACK_RLIMIT', 4194304)
288 if cc.get_id() == 'msvc'
289 ldflags += '/INCREMENTAL:NO'
290 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
291 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
293 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
294 # Need to allow multiple definitions, we e.g. want to override getopt.
295 ldflags += '-Wl,--allow-multiple-definition'
296 # Ensure we get MSVC-like linking behavior.
297 ldflags += '-Wl,--disable-auto-import'
300 os_deps += cc.find_library('ws2_32', required: true)
301 secur32_dep = cc.find_library('secur32', required: true)
302 backend_deps += secur32_dep
303 libpq_deps += secur32_dep
305 postgres_inc_d += 'src/include/port/win32'
306 if cc.get_id() == 'msvc'
307 postgres_inc_d += 'src/include/port/win32_msvc'
310 windows = import('windows')
313 # XXX: Should we add an option to override the host_system as an escape
315 error('unknown host system: @0@'.format(host_system))
320 ###############################################################
322 ###############################################################
325 perl = find_program(get_option('PERL'), required: true, native: true)
326 python = find_program(get_option('PYTHON'), required: true, native: true)
327 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
328 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
329 sed = find_program(get_option('SED'), 'sed', native: true)
330 prove = find_program(get_option('PROVE'), native: true, required: false)
331 tar = find_program(get_option('TAR'), native: true)
332 gzip = find_program(get_option('GZIP'), native: true)
333 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
334 touch = find_program('touch', native: true)
335 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
336 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
337 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
338 missing = find_program('config/missing', native: true)
342 bison_version_c = run_command(bison, '--version', check: true)
343 # bison version string helpfully is something like
344 # >>bison (GNU bison) 3.8.1<<
345 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
346 if bison_version.version_compare('>=3.0')
347 bison_flags += ['-Wno-deprecated']
350 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
352 'output': ['@BASENAME@.c', '@BASENAME@.h'],
353 'command': bison_cmd,
357 flex_wrapper = files('src/tools/pgflex')
358 flex_cmd = [python, flex_wrapper,
359 '--builddir', '@BUILD_ROOT@',
360 '--srcdir', '@SOURCE_ROOT@',
361 '--privatedir', '@PRIVATE_DIR@',
362 '--flex', flex, '--perl', perl,
363 '-i', '@INPUT@', '-o', '@OUTPUT0@',
366 wget = find_program('wget', required: false, native: true)
367 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
371 ###############################################################
372 # Path to meson (for tests etc)
373 ###############################################################
375 # NB: this should really be part of meson, see
376 # https://github.com/mesonbuild/meson/issues/8511
377 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
379 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
380 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
381 meson_binpath_r.returncode(),
382 meson_binpath_r.stdout(),
383 meson_binpath_r.stderr()))
386 meson_binpath_s = meson_binpath_r.stdout().split('\n')
387 meson_binpath_len = meson_binpath_s.length()
389 if meson_binpath_len < 1
390 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
397 foreach e : meson_binpath_s
408 if meson_impl not in ['muon', 'meson']
409 error('unknown meson implementation "@0@"'.format(meson_impl))
412 meson_bin = find_program(meson_binpath, native: true)
416 ###############################################################
418 ###############################################################
420 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
422 blocksize = get_option('blocksize').to_int() * 1024
424 if get_option('segsize_blocks') != 0
425 if get_option('segsize') != 1
426 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
429 segsize = get_option('segsize_blocks')
431 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
434 cdata.set('BLCKSZ', blocksize, description:
435 '''Size of a disk block --- this also limits the size of a tuple. You can set
436 it bigger if you need bigger tuples (although TOAST should reduce the need
437 to have large tuples, since fields can be spread across multiple tuples).
438 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
439 currently 2^15 (32768). This is determined by the 15-bit widths of the
440 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
441 Changing BLCKSZ requires an initdb.''')
443 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
444 cdata.set('RELSEG_SIZE', segsize)
445 cdata.set('DEF_PGPORT', get_option('pgport'))
446 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
447 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
448 if get_option('system_tzdata') != ''
449 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
454 ###############################################################
456 ###############################################################
458 # These are set by the equivalent --xxxdir configure options. We
459 # append "postgresql" to some of them, if the string does not already
460 # contain "pgsql" or "postgres", in order to avoid directory clutter.
464 dir_prefix = get_option('prefix')
466 dir_bin = get_option('bindir')
468 dir_data = get_option('datadir')
469 if not (dir_data.contains('pgsql') or dir_data.contains('postgres'))
470 dir_data = dir_data / pkg
473 dir_sysconf = get_option('sysconfdir')
474 if not (dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
475 dir_sysconf = dir_sysconf / pkg
478 dir_lib = get_option('libdir')
480 dir_lib_pkg = dir_lib
481 if not (dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
482 dir_lib_pkg = dir_lib_pkg / pkg
485 dir_pgxs = dir_lib_pkg / 'pgxs'
487 dir_include = get_option('includedir')
489 dir_include_pkg = dir_include
490 dir_include_pkg_rel = ''
491 if not (dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
492 dir_include_pkg = dir_include_pkg / pkg
493 dir_include_pkg_rel = pkg
496 dir_man = get_option('mandir')
498 # FIXME: These used to be separately configurable - worth adding?
499 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
500 dir_doc_html = dir_doc
502 dir_locale = get_option('localedir')
506 dir_bitcode = dir_lib_pkg / 'bitcode'
507 dir_include_internal = dir_include_pkg / 'internal'
508 dir_include_server = dir_include_pkg / 'server'
509 dir_include_extension = dir_include_server / 'extension'
510 dir_data_extension = dir_data / 'extension'
514 ###############################################################
515 # Search paths, preparation for compiler tests
517 # NB: Arguments added later are not automatically used for subsequent
518 # configuration-time checks (so they are more isolated). If they should be
519 # used, they need to be added to test_c_args as well.
520 ###############################################################
522 postgres_inc = [include_directories(postgres_inc_d)]
523 test_lib_d = postgres_lib_d
524 test_c_args = cppflags + cflags
528 ###############################################################
530 ###############################################################
532 bsd_authopt = get_option('bsd_auth')
533 bsd_auth = not_found_dep
534 if cc.check_header('bsd_auth.h', required: bsd_authopt,
535 args: test_c_args, include_directories: postgres_inc)
536 cdata.set('USE_BSD_AUTH', 1)
537 bsd_auth = declare_dependency()
542 ###############################################################
545 # For now don't search for DNSServiceRegister in a library - only Apple's
546 # Bonjour implementation, which is always linked, works.
547 ###############################################################
549 bonjouropt = get_option('bonjour')
550 bonjour = dependency('', required : false)
551 if cc.check_header('dns_sd.h', required: bonjouropt,
552 args: test_c_args, include_directories: postgres_inc) and \
553 cc.has_function('DNSServiceRegister',
554 args: test_c_args, include_directories: postgres_inc)
555 cdata.set('USE_BONJOUR', 1)
556 bonjour = declare_dependency()
561 ###############################################################
563 ###############################################################
565 gssapiopt = get_option('gssapi')
568 if not gssapiopt.disabled()
569 gssapi = dependency('krb5-gssapi', required: gssapiopt)
570 have_gssapi = gssapi.found()
573 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
574 args: test_c_args, include_directories: postgres_inc)
575 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
576 elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
577 cdata.set('HAVE_GSSAPI_H', 1)
583 elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
584 args: test_c_args, include_directories: postgres_inc)
585 cdata.set('ENABLE_GSS', 1)
587 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
588 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
589 elif gssapiopt.enabled()
590 error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
596 gssapi = not_found_dep
601 ###############################################################
603 ###############################################################
605 ldapopt = get_option('ldap')
606 if ldapopt.disabled()
608 ldap_r = not_found_dep
609 elif host_system == 'windows'
610 ldap = cc.find_library('wldap32', required: ldapopt)
613 # macos framework dependency is buggy for ldap (one can argue whether it's
614 # Apple's or meson's fault), leading to an endless recursion with ldap.h
615 # including itself. See https://github.com/mesonbuild/meson/issues/10002
616 # Luckily we only need pkg-config support, so the workaround isn't
618 ldap = dependency('ldap', method: 'pkg-config', required: false)
621 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
624 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
625 has_headers: 'ldap.h', header_include_directories: postgres_inc)
627 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
628 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
629 # library from a separate OpenLDAP installation). The most reliable
630 # way to check that is to check for a function introduced in 2.5.
632 # don't have ldap, we shouldn't check for ldap_r
633 elif cc.has_function('ldap_verify_credentials',
634 dependencies: ldap, args: test_c_args)
635 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
638 # Use ldap_r for FE if available, else assume ldap is thread-safe.
639 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
640 has_headers: 'ldap.h', header_include_directories: postgres_inc)
641 if not ldap_r.found()
644 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
645 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
648 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
649 # process. Check for OpenLDAP versions known not to tolerate doing so;
650 # assume non-OpenLDAP implementations are safe. The dblink test suite
651 # exercises the hazardous interaction directly.
652 compat_test_code = '''
654 #if !defined(LDAP_VENDOR_VERSION) || \
655 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
656 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
660 if not cc.compiles(compat_test_code,
661 name: 'LDAP implementation compatible',
662 dependencies: ldap, args: test_c_args)
664 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
665 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
666 *** also uses LDAP will crash on exit.''')
671 # XXX: this shouldn't be tested in the windows case, but should be tested in
672 # the dependency() success case
673 if ldap.found() and cc.has_function('ldap_initialize',
674 dependencies: ldap, args: test_c_args)
675 cdata.set('HAVE_LDAP_INITIALIZE', 1)
680 assert(ldap_r.found())
681 cdata.set('USE_LDAP', 1)
683 assert(not ldap_r.found())
688 ###############################################################
690 ###############################################################
692 llvmopt = get_option('llvm')
693 if not llvmopt.disabled()
694 add_languages('cpp', required: true, native: false)
695 llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
699 cdata.set('USE_LLVM', 1)
701 cpp = meson.get_compiler('cpp')
703 llvm_binpath = llvm.get_variable(configtool: 'bindir')
705 ccache = find_program('ccache', native: true, required: false)
706 clang = find_program(llvm_binpath / 'clang', required: true)
714 ###############################################################
716 ###############################################################
718 icuopt = get_option('icu')
719 if not icuopt.disabled()
720 icu = dependency('icu-uc', required: icuopt.enabled())
721 icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
724 cdata.set('USE_ICU', 1)
729 icu_i18n = not_found_dep
734 ###############################################################
736 ###############################################################
738 libxmlopt = get_option('libxml')
739 if not libxmlopt.disabled()
740 libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
743 cdata.set('USE_LIBXML', 1)
746 libxml = not_found_dep
751 ###############################################################
753 ###############################################################
755 libxsltopt = get_option('libxslt')
756 if not libxsltopt.disabled()
757 libxslt = dependency('libxslt', required: libxsltopt)
760 cdata.set('USE_LIBXSLT', 1)
763 libxslt = not_found_dep
768 ###############################################################
770 ###############################################################
772 lz4opt = get_option('lz4')
773 if not lz4opt.disabled()
774 lz4 = dependency('liblz4', required: lz4opt)
777 cdata.set('USE_LZ4', 1)
778 cdata.set('HAVE_LIBLZ4', 1)
787 ###############################################################
788 # Library: Tcl (for pltcl)
790 # NB: tclConfig.sh is used in autoconf build for getting
791 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
792 # variables. For now we have not seen a need to copy
793 # that behaviour to the meson build.
794 ###############################################################
796 tclopt = get_option('pltcl')
797 tcl_version = get_option('tcl_version')
798 tcl_dep = not_found_dep
799 if not tclopt.disabled()
802 tcl_dep = dependency(tcl_version, required: false)
804 if not tcl_dep.found()
805 tcl_dep = cc.find_library(tcl_version,
810 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
811 tcl_dep = not_found_dep
817 ###############################################################
819 ###############################################################
821 pamopt = get_option('pam')
822 if not pamopt.disabled()
823 pam = dependency('pam', required: false)
826 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
830 pam_header_found = false
832 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
833 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
834 args: test_c_args, include_directories: postgres_inc)
835 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
836 pam_header_found = true
837 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
838 args: test_c_args, include_directories: postgres_inc)
839 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
840 pam_header_found = true
844 cdata.set('USE_PAM', 1)
855 ###############################################################
856 # Library: Perl (for plperl)
857 ###############################################################
859 perlopt = get_option('plperl')
860 perl_dep = not_found_dep
861 if not perlopt.disabled()
864 # First verify that perl has the necessary dependencies installed
865 perl_mods = run_command(
867 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
870 if perl_mods.returncode() != 0
871 perl_may_work = false
872 perl_msg = 'perl installation does not have the required modules'
875 # Then inquire perl about its configuration
877 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
878 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
879 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
880 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
881 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
883 perl_inc_dir = '@0@/CORE'.format(archlibexp)
885 if perlversion.version_compare('< 5.14')
886 perl_may_work = false
887 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
888 elif useshrplib != 'true'
889 perl_may_work = false
890 perl_msg = 'need a shared perl'
895 # On most platforms, archlibexp is also where the Perl include files live ...
896 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
897 # ... but on newer macOS versions, we must use -iwithsysroot to look
899 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
900 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
901 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
904 # check compiler finds header
905 if not cc.has_header('perl.h', required: false,
906 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
907 perl_may_work = false
908 perl_msg = 'missing perl.h'
913 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
915 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
916 foreach flag : perl_ccflags_r.split(' ')
917 if flag.startswith('-D') and \
918 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
923 if host_system == 'windows'
924 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
926 if cc.get_id() == 'msvc'
927 # prevent binary mismatch between MSVC built plperl and Strawberry or
928 # msys ucrt perl libraries
929 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
933 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
934 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
936 # We are after Embed's ldopts, but without the subset mentioned in
937 # Config's ccdlflags and ldflags. (Those are the choices of those who
938 # built the Perl installation, which are not necessarily appropriate
939 # for building PostgreSQL.)
940 ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
941 undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
942 undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
945 foreach ldopt : ldopts.split(' ')
946 if ldopt == '' or ldopt in undesired
950 perl_ldopts += ldopt.strip('"')
953 message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
954 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
956 perl_dep_int = declare_dependency(
957 compile_args: perl_ccflags,
958 link_args: perl_ldopts,
959 version: perlversion,
962 # While we're at it, check that we can link to libperl.
963 # On most platforms, if perl.h is there then libperl.so will be too, but
964 # at this writing Debian packages them separately.
968 #define __inline__ inline
976 if not cc.links(perl_link_test, name: 'libperl',
977 args: test_c_args + perl_ccflags + perl_ldopts,
978 include_directories: postgres_inc)
979 perl_may_work = false
980 perl_msg = 'missing libperl'
983 endif # perl_may_work
986 perl_dep = perl_dep_int
989 error('dependency plperl failed: @0@'.format(perl_msg))
991 message('disabling optional dependency plperl: @0@'.format(perl_msg))
998 ###############################################################
999 # Library: Python (for plpython)
1000 ###############################################################
1002 pyopt = get_option('plpython')
1003 if not pyopt.disabled()
1004 pm = import('python')
1005 python3_inst = pm.find_installation(required: pyopt.enabled())
1006 python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
1007 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
1008 python3_dep = not_found_dep
1011 python3_dep = not_found_dep
1016 ###############################################################
1018 ###############################################################
1020 if not get_option('readline').disabled()
1021 libedit_preferred = get_option('libedit_preferred')
1022 # Set the order of readline dependencies
1023 check_readline_deps = libedit_preferred ? \
1024 ['libedit', 'readline'] : ['readline', 'libedit']
1026 foreach readline_dep : check_readline_deps
1027 readline = dependency(readline_dep, required: false)
1028 if not readline.found()
1029 readline = cc.find_library(readline_dep,
1030 required: get_option('readline').enabled(),
1039 cdata.set('HAVE_LIBREADLINE', 1)
1042 'header_prefix': 'editline/',
1043 'flag_prefix': 'EDITLINE_',
1046 'header_prefix': 'readline/',
1047 'flag_prefix': 'READLINE_',
1050 'header_prefix': '',
1054 # Set the order of prefixes
1055 prefixes = libedit_preferred ? \
1056 [editline_prefix, default_prefix, readline_prefix] : \
1057 [readline_prefix, default_prefix, editline_prefix]
1059 at_least_one_header_found = false
1060 foreach header : ['history', 'readline']
1062 foreach prefix : prefixes
1063 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1064 # Check history.h and readline.h
1065 if not is_found and cc.has_header(header_file,
1066 args: test_c_args, include_directories: postgres_inc,
1067 dependencies: [readline], required: false)
1068 if header == 'readline'
1069 readline_h = header_file
1071 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1073 at_least_one_header_found = true
1078 if not at_least_one_header_found
1079 error('''readline header not found
1080 If you have @0@ already installed, see see meson-log/meson-log.txt for details on the
1081 failure. It is possible the compiler isn't looking in the proper directory.
1082 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1087 'history_truncate_file',
1088 'rl_completion_matches',
1089 'rl_filename_completion_function',
1090 'rl_reset_screen_size',
1094 foreach func : check_funcs
1095 found = cc.has_function(func, dependencies: [readline],
1096 args: test_c_args, include_directories: postgres_inc)
1097 cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1101 'rl_completion_suppress_quote',
1102 'rl_filename_quote_characters',
1103 'rl_filename_quoting_function',
1106 foreach var : check_vars
1107 cdata.set('HAVE_'+var.to_upper(),
1108 cc.has_header_symbol(readline_h, var,
1109 args: test_c_args, include_directories: postgres_inc,
1110 prefix: '#include <stdio.h>',
1111 dependencies: [readline]) ? 1 : false)
1114 # If found via cc.find_library() ensure headers are found when using the
1115 # dependency. On meson < 0.57 one cannot do compiler checks using the
1116 # dependency returned by declare_dependency(), so we can't do this above.
1117 if readline.type_name() == 'library'
1118 readline = declare_dependency(dependencies: readline,
1119 include_directories: postgres_inc)
1122 # On windows with mingw readline requires auto-import to successfully
1123 # link, as the headers don't use declspec(dllimport)
1124 if host_system == 'windows' and cc.get_id() != 'msvc'
1125 readline = declare_dependency(dependencies: readline,
1126 link_args: '-Wl,--enable-auto-import')
1130 # XXX: Figure out whether to implement mingw warning equivalent
1132 readline = not_found_dep
1137 ###############################################################
1139 ###############################################################
1141 selinux = not_found_dep
1142 selinuxopt = get_option('selinux')
1143 if meson.version().version_compare('>=0.59')
1144 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1146 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1147 cdata.set('HAVE_LIBSELINUX',
1148 selinux.found() ? 1 : false)
1152 ###############################################################
1154 ###############################################################
1156 systemd = not_found_dep
1157 systemdopt = get_option('systemd')
1158 if meson.version().version_compare('>=0.59')
1159 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1161 systemd = dependency('libsystemd', required: systemdopt)
1162 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1166 ###############################################################
1168 ###############################################################
1170 if get_option('ssl') == 'openssl'
1172 # Try to find openssl via pkg-config et al, if that doesn't work
1173 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1174 # the library names that we know about.
1176 # via pkg-config et al
1177 ssl = dependency('openssl', required: false)
1179 # via library + headers
1181 ssl_lib = cc.find_library('ssl',
1183 header_include_directories: postgres_inc,
1184 has_headers: ['openssl/ssl.h', 'openssl/err.h'])
1185 crypto_lib = cc.find_library('crypto',
1187 header_include_directories: postgres_inc)
1188 ssl_int = [ssl_lib, crypto_lib]
1190 ssl = declare_dependency(dependencies: ssl_int,
1191 include_directories: postgres_inc)
1193 cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
1194 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
1200 ['CRYPTO_new_ex_data', {'required': true}],
1201 ['SSL_new', {'required': true}],
1203 # Function introduced in OpenSSL 1.0.2.
1204 ['X509_get_signature_nid'],
1206 # Functions introduced in OpenSSL 1.1.0. We used to check for
1207 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1208 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1209 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1211 ['OPENSSL_init_ssl'],
1214 ['ASN1_STRING_get0_data'],
1218 # OpenSSL versions before 1.1.0 required setting callback functions, for
1219 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1220 # function was removed.
1224 foreach c : check_funcs
1226 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1227 required = c.get(1, {}).get('required', false)
1228 if required and not val
1229 error('openssl function @0@ is required'.format(func))
1231 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1235 cdata.set('USE_OPENSSL', 1,
1236 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1237 cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1238 description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1245 ###############################################################
1247 ###############################################################
1249 uuidopt = get_option('uuid')
1250 if uuidopt != 'none'
1251 uuidname = uuidopt.to_upper()
1252 if uuidopt == 'e2fs'
1253 uuid = dependency('uuid', required: true)
1254 uuidfunc = 'uuid_generate'
1255 uuidheader = 'uuid/uuid.h'
1256 elif uuidopt == 'bsd'
1257 # libc should have uuid function
1258 uuid = declare_dependency()
1259 uuidfunc = 'uuid_to_string'
1260 uuidheader = 'uuid.h'
1261 elif uuidopt == 'ossp'
1262 uuid = dependency('ossp-uuid', required: true)
1263 uuidfunc = 'uuid_export'
1264 uuidheader = 'ossp/uuid.h'
1269 if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1270 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1272 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1274 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1275 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1277 uuid = not_found_dep
1282 ###############################################################
1284 ###############################################################
1286 zlibopt = get_option('zlib')
1287 zlib = not_found_dep
1288 if not zlibopt.disabled()
1289 zlib_t = dependency('zlib', required: zlibopt)
1291 if zlib_t.type_name() == 'internal'
1292 # if fallback was used, we don't need to test if headers are present (they
1293 # aren't built yet, so we can't test)
1295 elif not zlib_t.found()
1296 warning('did not find zlib')
1297 elif not cc.has_header('zlib.h',
1298 args: test_c_args, include_directories: postgres_inc,
1299 dependencies: [zlib_t], required: zlibopt.enabled())
1300 warning('zlib header not found')
1301 elif not cc.has_type('z_streamp',
1302 dependencies: [zlib_t], prefix: '#include <zlib.h>',
1303 args: test_c_args, include_directories: postgres_inc)
1304 if zlibopt.enabled()
1305 error('zlib version is too old')
1307 warning('zlib version is too old')
1314 cdata.set('HAVE_LIBZ', 1)
1320 ###############################################################
1321 # Library: tap test dependencies
1322 ###############################################################
1324 # Check whether tap tests are enabled or not
1325 tap_tests_enabled = false
1326 tapopt = get_option('tap_tests')
1327 if not tapopt.disabled()
1328 # Checking for perl modules for tap tests
1329 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1330 if perl_ipc_run_check.returncode() != 0
1331 message(perl_ipc_run_check.stderr().strip())
1333 error('Additional Perl modules are required to run TAP tests.')
1335 warning('Additional Perl modules are required to run TAP tests.')
1338 tap_tests_enabled = true
1344 ###############################################################
1346 ###############################################################
1348 zstdopt = get_option('zstd')
1349 if not zstdopt.disabled()
1350 zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1353 cdata.set('USE_ZSTD', 1)
1354 cdata.set('HAVE_LIBZSTD', 1)
1358 zstd = not_found_dep
1363 ###############################################################
1365 ###############################################################
1367 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1368 # unnecessarily, because we optionally rely on newer features.
1370 #include <stdbool.h>
1371 #include <complex.h>
1373 #include <inttypes.h>
1375 struct named_init_test {
1380 extern void structfunc(struct named_init_test);
1382 int main(int argc, char **argv)
1384 struct named_init_test nit = {
1389 for (int loop_var = 0; loop_var < 3; loop_var++)
1394 structfunc((struct named_init_test){1, 0});
1400 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1401 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1402 args: test_c_args + ['-std=c99'])
1403 test_c_args += '-std=c99'
1404 cflags += '-std=c99'
1406 error('C compiler does not support C99')
1410 sizeof_long = cc.sizeof('long', args: test_c_args)
1411 cdata.set('SIZEOF_LONG', sizeof_long)
1413 cdata.set('HAVE_LONG_INT_64', 1)
1414 cdata.set('PG_INT64_TYPE', 'long int')
1415 cdata.set_quoted('INT64_MODIFIER', 'l')
1416 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1417 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1418 cdata.set('PG_INT64_TYPE', 'long long int')
1419 cdata.set_quoted('INT64_MODIFIER', 'll')
1421 error('do not know how to get a 64bit int')
1424 if host_machine.endian() == 'big'
1425 cdata.set('WORDS_BIGENDIAN', 1)
1428 alignof_types = ['short', 'int', 'long', 'double']
1430 foreach t : alignof_types
1431 align = cc.alignment(t, args: test_c_args)
1435 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1437 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1439 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1440 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1443 # Check if __int128 is a working 128 bit integer type, and if so
1444 # define PG_INT128_TYPE to that typename.
1446 # This currently only detects a GCC/clang extension, but support for other
1447 # environments may be added in the future.
1449 # For the moment we only test for support for 128bit math; support for
1450 # 128bit literals and snprintf is not required.
1453 * We don't actually run this test, just link it to verify that any support
1454 * functions needed for __int128 are present.
1456 * These are globals to discourage the compiler from folding all the
1457 * arithmetic tests down to compile-time constants. We do not have
1458 * convenient support for 128bit literals at this point...
1460 __int128 a = 48828125;
1461 __int128 b = 97656250;
1466 a = (a << 12) + 1; /* 200000000001 */
1467 b = (b << 12) + 5; /* 400000000005 */
1468 /* try the most relevant arithmetic ops */
1471 /* must use the results, else compiler may optimize arithmetic away */
1477 buggy_int128 = false
1479 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1480 # If not cross-compiling, we can test for bugs and disable use of __int128
1481 # with buggy compilers. If cross-compiling, hope for the best.
1482 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1483 if not meson.is_cross_build()
1485 /* This must match the corresponding code in c.h: */
1486 #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1487 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1488 #elif defined(_MSC_VER)
1489 #define pg_attribute_aligned(a) __declspec(align(a))
1491 typedef __int128 int128a
1492 #if defined(pg_attribute_aligned)
1493 pg_attribute_aligned(8)
1498 void pass_by_val(void *buffer, int128a par) { holder = par; }
1502 long int i64 = 97656225L << 12;
1504 pass_by_val(main, (int128a) i64);
1508 name: '__int128 alignment bug',
1510 assert(r.compiled())
1511 if r.returncode() != 0
1513 message('__int128 support present but buggy and thus disabled')
1518 cdata.set('PG_INT128_TYPE', '__int128')
1519 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1520 alignment('__int128', args: test_c_args))
1525 # Check if the C compiler knows computed gotos (gcc extension, also
1526 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1528 # Checking whether computed gotos are supported syntax-wise ought to
1529 # be enough, as the syntax is otherwise illegal.
1531 static inline int foo(void)
1533 void *labeladdrs[] = {&&my_label};
1534 goto *labeladdrs[0];
1539 cdata.set('HAVE_COMPUTED_GOTO', 1)
1543 # Check if the C compiler understands _Static_assert(),
1544 # and define HAVE__STATIC_ASSERT if so.
1546 # We actually check the syntax ({ _Static_assert(...) }), because we need
1547 # gcc-style compound expressions to be able to wrap the thing into macros.
1549 int main(int arg, char **argv)
1551 ({ _Static_assert(1, "foo"); });
1555 cdata.set('HAVE__STATIC_ASSERT', 1)
1559 # We use <stdbool.h> if we have it and it declares type bool as having
1560 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1561 if cc.has_type('_Bool', args: test_c_args) \
1562 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1563 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1564 cdata.set('HAVE__BOOL', 1)
1565 cdata.set('PG_USE_STDBOOL', 1)
1569 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1570 # warning for each use of %m.
1571 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1573 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1574 static void call_log(void)
1576 emit_log(0, "error: %s: %m", "foo");
1579 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1580 foreach a : printf_attributes
1581 if cc.compiles(testsrc.format(a),
1582 args: test_c_args + attrib_error_args, name: 'format ' + a)
1583 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1589 if cc.has_function_attribute('visibility:default') and \
1590 cc.has_function_attribute('visibility:hidden')
1591 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1593 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1594 # inlineshidden to C code as well... Any either way, we want to put these
1595 # flags into exported files (pgxs, .pc files).
1596 cflags_mod += '-fvisibility=hidden'
1597 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1598 ldflags_mod += '-fvisibility=hidden'
1602 # Check if various builtins exist. Some builtins are tested separately,
1603 # because we want to test something more complicated than the generic case.
1616 foreach builtin : builtins
1617 fname = '__builtin_@0@'.format(builtin)
1618 if cc.has_function(fname, args: test_c_args)
1619 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1624 # Check if the C compiler understands __builtin_types_compatible_p,
1625 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1627 # We check usage with __typeof__, though it's unlikely any compiler would
1628 # have the former and not the latter.
1631 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1633 name: '__builtin_types_compatible_p',
1635 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1639 # Check if the C compiler understands __builtin_$op_overflow(),
1640 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1642 # Check for the most complicated case, 64 bit multiplication, as a
1643 # proxy for all of the operations. To detect the case where the compiler
1644 # knows the function but library support is missing, we must link not just
1645 # compile, and store the results in global variables so the compiler doesn't
1646 # optimize away the call.
1654 return __builtin_mul_overflow(a, b, &result);
1656 name: '__builtin_mul_overflow',
1657 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1659 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1663 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1664 # here. To prevent problems due to two detection methods working, stop
1665 # checking after one.
1668 int main(int arg, char **argv)
1670 unsigned int exx[4] = {0, 0, 0, 0};
1671 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1673 ''', name: '__get_cpuid',
1675 cdata.set('HAVE__GET_CPUID', 1)
1678 int main(int arg, char **argv)
1680 unsigned int exx[4] = {0, 0, 0, 0};
1683 ''', name: '__cpuid',
1685 cdata.set('HAVE__CPUID', 1)
1689 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1690 # versions of clang do not understand -fexcess-precision=standard, the use of
1691 # x87 floating point operations leads to problems like isinf possibly returning
1692 # false for a value that is infinite when converted from the 80bit register to
1693 # the 8byte memory representation.
1695 # Only perform the test if the compiler doesn't understand
1696 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1698 if '-fexcess-precision=standard' not in cflags
1699 if not cc.compiles('''
1700 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1703 name: '', args: test_c_args)
1704 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1710 ###############################################################
1712 ###############################################################
1714 common_functional_flags = [
1715 # Disable strict-aliasing rules; needed for gcc 3.3+
1716 '-fno-strict-aliasing',
1717 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1719 '-fexcess-precision=standard',
1722 cflags += cc.get_supported_arguments(common_functional_flags)
1724 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1727 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1728 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1730 common_warning_flags = [
1731 '-Wmissing-prototypes',
1733 # Really don't want VLAs to be used in our dialect of C
1735 # On macOS, complain about usage of symbols newer than the deployment target
1736 '-Werror=unguarded-availability-new',
1738 '-Wmissing-format-attribute',
1739 '-Wimplicit-fallthrough=3',
1740 '-Wcast-function-type',
1741 '-Wshadow=compatible-local',
1742 # This was included in -Wall/-Wformat in older GCC versions
1743 '-Wformat-security',
1746 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1748 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1751 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1752 # the result for them
1753 cflags_no_decl_after_statement = []
1754 if cc.has_argument('-Wdeclaration-after-statement')
1755 cflags_warn += '-Wdeclaration-after-statement'
1756 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1760 # The following tests want to suppress various unhelpful warnings by adding
1761 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1762 # switches, so we have to test for the positive form and if that works,
1763 # add the negative form.
1765 negative_warning_flags = [
1766 # Suppress clang's unhelpful unused-command-line-argument warnings.
1767 'unused-command-line-argument',
1769 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1770 # of warnings when building plperl because of usages in the Perl headers.
1771 'compound-token-split-by-macro',
1773 # Similarly disable useless truncation warnings from gcc 8+
1774 'format-truncation',
1775 'stringop-truncation',
1777 # To make warning_level=2 / -Wextra work, we'd need at least the following
1779 # 'missing-field-initializers',
1781 # 'unused-parameter',
1784 foreach w : negative_warning_flags
1785 if cc.has_argument('-W' + w)
1786 cflags_warn += '-Wno-' + w
1788 if llvm.found() and cpp.has_argument('-W' + w)
1789 cxxflags_warn += '-Wno-' + w
1795 if cc.get_id() == 'msvc'
1797 '/wd4018', # signed/unsigned mismatch
1798 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1799 '/wd4273', # inconsistent DLL linkage
1800 '/wd4101', # unreferenced local variable
1801 '/wd4102', # unreferenced label
1802 '/wd4090', # different 'modifier' qualifiers
1803 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1811 '/D_CRT_SECURE_NO_DEPRECATE',
1812 '/D_CRT_NONSTDC_NO_DEPRECATE',
1815 # We never need export libraries. As link.exe reports their creation, they
1816 # are unnecessarily noisy. Similarly, we don't need import library for
1817 # modules, we only import them dynamically, and they're also noisy.
1819 ldflags_mod += '/NOIMPLIB'
1824 ###############################################################
1826 ###############################################################
1828 if not get_option('spinlocks')
1829 warning('Not using spinlocks will cause poor performance')
1831 cdata.set('HAVE_SPINLOCKS', 1)
1834 if not get_option('atomics')
1835 warning('Not using atomics will cause poor performance')
1837 # XXX: perhaps we should require some atomics support in this case these
1839 cdata.set('HAVE_ATOMICS', 1)
1842 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1843 'desc': '__sync_lock_test_and_set(char)',
1846 __sync_lock_test_and_set(&lock, 1);
1847 __sync_lock_release(&lock);'''},
1849 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1850 'desc': '__sync_lock_test_and_set(int32)',
1853 __sync_lock_test_and_set(&lock, 1);
1854 __sync_lock_release(&lock);'''},
1856 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1857 'desc': '__sync_val_compare_and_swap(int32)',
1860 __sync_val_compare_and_swap(&val, 0, 37);'''},
1862 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1863 'desc': '__sync_val_compare_and_swap(int64)',
1866 __sync_val_compare_and_swap(&val, 0, 37);'''},
1868 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1869 'desc': ' __atomic_compare_exchange_n(int32)',
1873 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1875 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1876 'desc': ' __atomic_compare_exchange_n(int64)',
1880 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1883 foreach check : atomic_checks
1888 }'''.format(check['test'])
1890 cdata.set(check['name'],
1892 name: check['desc'],
1893 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1901 ###############################################################
1902 # Select CRC-32C implementation.
1904 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1905 # use the special CRC instructions for calculating CRC-32C. If we're not
1906 # targeting such a processor, but we can nevertheless produce code that uses
1907 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1908 # implementations and select which one to use at runtime, depending on whether
1909 # SSE 4.2 is supported by the processor we're running on.
1911 # Similarly, if we are targeting an ARM processor that has the CRC
1912 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1913 # we're not targeting such a processor, but can nevertheless produce code that
1914 # uses the CRC instructions, compile both, and select at runtime.
1915 ###############################################################
1917 have_optimized_crc = false
1919 if host_cpu == 'x86' or host_cpu == 'x86_64'
1921 if cc.get_id() == 'msvc'
1922 cdata.set('USE_SSE42_CRC32C', false)
1923 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1924 have_optimized_crc = true
1928 #include <nmmintrin.h>
1932 unsigned int crc = 0;
1933 crc = _mm_crc32_u8(crc, 0);
1934 crc = _mm_crc32_u32(crc, 0);
1935 /* return computed value, to prevent the above being optimized away */
1940 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
1942 # Use Intel SSE 4.2 unconditionally.
1943 cdata.set('USE_SSE42_CRC32C', 1)
1944 have_optimized_crc = true
1945 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
1946 args: test_c_args + ['-msse4.2'])
1947 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
1948 # the runtime check.
1949 cflags_crc += '-msse4.2'
1950 cdata.set('USE_SSE42_CRC32C', false)
1951 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1952 have_optimized_crc = true
1957 elif host_cpu == 'arm' or host_cpu == 'aarch64'
1960 #include <arm_acle.h>
1964 unsigned int crc = 0;
1965 crc = __crc32cb(crc, 0);
1966 crc = __crc32ch(crc, 0);
1967 crc = __crc32cw(crc, 0);
1968 crc = __crc32cd(crc, 0);
1970 /* return computed value, to prevent the above being optimized away */
1975 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
1977 # Use ARM CRC Extension unconditionally
1978 cdata.set('USE_ARMV8_CRC32C', 1)
1979 have_optimized_crc = true
1980 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
1981 args: test_c_args + ['-march=armv8-a+crc'])
1982 # Use ARM CRC Extension, with runtime check
1983 cflags_crc += '-march=armv8-a+crc'
1984 cdata.set('USE_ARMV8_CRC32C', false)
1985 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
1986 have_optimized_crc = true
1990 if not have_optimized_crc
1991 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
1993 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
1998 ###############################################################
1999 # Other CPU specific stuff
2000 ###############################################################
2002 if host_cpu == 'x86_64'
2007 long long x = 1; long long r;
2008 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2010 name: '@0@: popcntq instruction'.format(host_cpu),
2012 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2015 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2016 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2017 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2020 addi(int ra, int si)
2023 if (__builtin_constant_p(si))
2024 __asm__ __volatile__(
2025 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2028 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2031 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2038 ###############################################################
2039 # Library / OS tests
2040 ###############################################################
2042 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2043 # unnecessary checks over and over, particularly on windows.
2057 'sys/personality.h',
2066 foreach header : header_checks
2067 varname = 'HAVE_' + header.underscorify().to_upper()
2069 # Emulate autoconf behaviour of not-found->undef, found->1
2070 found = cc.has_header(header,
2071 include_directories: postgres_inc, args: test_c_args)
2072 cdata.set(varname, found ? 1 : false,
2073 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2078 ['F_FULLFSYNC', 'fcntl.h'],
2079 ['fdatasync', 'unistd.h'],
2080 ['posix_fadvise', 'fcntl.h'],
2081 ['strlcat', 'string.h'],
2082 ['strlcpy', 'string.h'],
2083 ['strnlen', 'string.h'],
2086 # Need to check for function declarations for these functions, because
2087 # checking for library symbols wouldn't handle deployment target
2088 # restrictions on macOS
2090 ['preadv', 'sys/uio.h'],
2091 ['pwritev', 'sys/uio.h'],
2094 foreach c : decl_checks
2098 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2100 found = cc.has_header_symbol(header, func,
2101 args: test_c_args, include_directories: postgres_inc,
2103 cdata.set10(varname, found, description:
2104 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2105 don't.'''.format(func))
2109 if cc.has_type('struct cmsgcred',
2110 args: test_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? '' : '-DHAVE_SYS_UCRED_H'],
2111 include_directories: postgres_inc,
2113 #include <sys/socket.h>
2114 #include <sys/param.h>
2115 #ifdef HAVE_SYS_UCRED_H
2116 #include <sys/ucred.h>
2118 cdata.set('HAVE_STRUCT_CMSGCRED', 1)
2120 cdata.set('HAVE_STRUCT_CMSGCRED', false)
2123 if cc.has_type('struct option',
2124 args: test_c_args, include_directories: postgres_inc,
2125 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2126 cdata.set('HAVE_STRUCT_OPTION', 1)
2130 foreach c : ['opterr', 'optreset']
2131 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2140 '''.format(c), name: c, args: test_c_args)
2141 cdata.set(varname, 1)
2143 cdata.set(varname, false)
2147 if cc.has_type('socklen_t',
2148 args: test_c_args, include_directories: postgres_inc,
2150 #include <sys/socket.h>''')
2151 cdata.set('HAVE_SOCKLEN_T', 1)
2154 if cc.has_member('struct sockaddr', 'sa_len',
2155 args: test_c_args, include_directories: postgres_inc,
2157 #include <sys/types.h>
2158 #include <sys/socket.h>''')
2159 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2162 if cc.has_member('struct tm', 'tm_zone',
2163 args: test_c_args, include_directories: postgres_inc,
2165 #include <sys/types.h>
2168 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2173 extern int foo(void);
2176 return timezone / 60;
2179 name: 'global variable `timezone\' exists',
2180 args: test_c_args, include_directories: postgres_inc)
2181 cdata.set('HAVE_INT_TIMEZONE', 1)
2183 cdata.set('HAVE_INT_TIMEZONE', false)
2186 if cc.has_type('union semun',
2188 include_directories: postgres_inc,
2190 #include <sys/types.h>
2191 #include <sys/ipc.h>
2192 #include <sys/sem.h>
2194 cdata.set('HAVE_UNION_SEMUN', 1)
2202 switch (strerror_r(1, buf, sizeof(buf)))
2203 { case 0: break; default: break; }
2206 args: test_c_args, include_directories: postgres_inc)
2207 cdata.set('STRERROR_R_INT', 1)
2209 cdata.set('STRERROR_R_INT', false)
2212 # Check for the locale_t type and find the right header file. macOS
2213 # needs xlocale.h; standard is locale.h, but glibc also has an
2214 # xlocale.h file that we should not use. MSVC has a replacement
2215 # defined in src/include/port/win32_port.h.
2216 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2217 cdata.set('HAVE_LOCALE_T', 1)
2218 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2219 cdata.set('HAVE_LOCALE_T', 1)
2220 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2221 elif cc.get_id() == 'msvc'
2222 cdata.set('HAVE_LOCALE_T', 1)
2225 # Check if the C compiler understands typeof or a variant. Define
2226 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2227 foreach kw : ['typeof', '__typeof__', 'decltype']
2238 args: test_c_args, include_directories: postgres_inc)
2240 cdata.set('HAVE_TYPEOF', 1)
2242 cdata.set('typeof', kw)
2250 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2251 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2252 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2253 wcstombs_l_test = '''
2265 if (not cc.compiles(wcstombs_l_test.format(''),
2266 name: 'wcstombs_l') and
2267 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2268 name: 'wcstombs_l in xlocale.h'))
2269 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2273 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2274 # understands, because it conflicts with __declspec(restrict). Therefore we
2275 # define pg_restrict to the appropriate definition, which presumably won't
2278 # We assume C99 support, so we don't need to make this conditional.
2280 # XXX: Historically we allowed platforms to disable restrict in template
2281 # files, but that was only added for AIX when building with XLC, which we
2282 # don't support yet.
2283 cdata.set('pg_restrict', '__restrict')
2287 #include <machine/vmparam.h>
2288 #include <sys/exec.h>
2292 PS_STRINGS->ps_nargvstr = 1;
2293 PS_STRINGS->ps_argvstr = "foo";
2296 name: 'PS_STRINGS', args: test_c_args)
2297 cdata.set('HAVE_PS_STRINGS', 1)
2299 cdata.set('HAVE_PS_STRINGS', false)
2303 # Most libraries are included only if they demonstrably provide a function we
2304 # need, but libm is an exception: always include it, because there are too
2305 # many compilers that play cute optimization games that will break probes for
2306 # standard functions such as pow().
2307 os_deps += cc.find_library('m', required: false)
2309 rt_dep = cc.find_library('rt', required: false)
2311 dl_dep = cc.find_library('dl', required: false)
2313 util_dep = cc.find_library('util', required: false)
2314 posix4_dep = cc.find_library('posix4', required: false)
2316 getopt_dep = cc.find_library('getopt', required: false)
2317 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2318 # Check if we want to replace getopt/getopt_long even if provided by the system
2319 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2320 # so always use our version on Windows
2321 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2322 # (i.e., allow '-' as a flag character), so use our version on those platforms
2323 # - We want to use system's getopt_long() only if the system provides struct
2325 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2326 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2329 execinfo_dep = cc.find_library('execinfo', required: false)
2331 if host_system == 'cygwin'
2332 cygipc_dep = cc.find_library('cygipc', required: false)
2334 cygipc_dep = not_found_dep
2337 if host_system == 'sunos'
2338 socket_dep = cc.find_library('socket', required: false)
2340 socket_dep = not_found_dep
2343 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2344 # unnecessary checks over and over, particularly on windows.
2346 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2347 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2348 ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2350 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2351 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2352 # required. Just checking for dlsym() ought to suffice.
2353 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2355 ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2357 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2358 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2368 ['posix_fallocate'],
2371 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2372 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2373 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2374 ['setproctitle', {'dependencies': [util_dep]}],
2375 ['setproctitle_fast'],
2376 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2377 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2378 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2379 ['socket', {'dependencies': [socket_dep], 'define': false}],
2381 ['strerror_r', {'dependencies': [thread_dep]}],
2386 ['sync_file_range'],
2392 func_check_results = {}
2393 foreach c : func_checks
2395 kwargs = c.get(1, {})
2396 deps = kwargs.get('dependencies', [])
2398 if kwargs.get('skip', false)
2402 found = cc.has_function(func, args: test_c_args)
2409 found = cc.has_function(func, args: test_c_args,
2410 dependencies: [dep])
2418 func_check_results += {func: found}
2420 if kwargs.get('define', true)
2421 # Emulate autoconf behaviour of not-found->undef, found->1
2422 cdata.set('HAVE_' + func.underscorify().to_upper(),
2424 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2429 if cc.has_function('syslog', args: test_c_args) and \
2430 cc.check_header('syslog.h', args: test_c_args)
2431 cdata.set('HAVE_SYSLOG', 1)
2435 # MSVC has replacements defined in src/include/port/win32_port.h.
2436 if cc.get_id() == 'msvc'
2437 cdata.set('HAVE_WCSTOMBS_L', 1)
2438 cdata.set('HAVE_MBSTOWCS_L', 1)
2442 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2444 if sema_kind == 'unnamed_posix' and \
2445 not func_check_results.get('sem_init', false)
2449 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2450 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2452 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2453 cdata.set_quoted('DLSUFFIX', dlsuffix)
2457 ###############################################################
2459 ###############################################################
2461 # XXX: About to rely on thread safety in the autoconf build, so not worth
2462 # implementing a fallback.
2463 cdata.set('ENABLE_THREAD_SAFETY', 1)
2467 ###############################################################
2469 ###############################################################
2471 nlsopt = get_option('nls')
2472 libintl = not_found_dep
2474 if not nlsopt.disabled()
2475 # otherwise there'd be lots of
2476 # "Gettext not found, all translation (po) targets will be ignored."
2477 # warnings if not found.
2478 msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2480 # meson 0.59 has this wrapped in dependency('int')
2481 if (msgfmt.found() and
2482 cc.check_header('libintl.h', required: nlsopt,
2483 args: test_c_args, include_directories: postgres_inc))
2486 if cc.has_function('ngettext')
2487 libintl = declare_dependency()
2489 libintl = cc.find_library('intl',
2490 has_headers: ['libintl.h'], required: nlsopt,
2491 header_include_directories: postgres_inc,
2497 i18n = import('i18n')
2498 cdata.set('ENABLE_NLS', 1)
2504 ###############################################################
2506 ###############################################################
2508 # Set up compiler / linker arguments to be used everywhere, individual targets
2509 # can add further args directly, or indirectly via dependencies
2510 add_project_arguments(cflags, language: ['c'])
2511 add_project_arguments(cppflags, language: ['c'])
2512 add_project_arguments(cflags_warn, language: ['c'])
2513 add_project_arguments(cxxflags, language: ['cpp'])
2514 add_project_arguments(cppflags, language: ['cpp'])
2515 add_project_arguments(cxxflags_warn, language: ['cpp'])
2516 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2519 # Collect a number of lists of things while recursing through the source
2520 # tree. Later steps then can use those.
2522 # list of targets for various alias targets
2523 backend_targets = []
2526 contrib_targets = []
2527 testprep_targets = []
2530 # Define the tests to distribute them to the correct test styles later
2535 # Default options for targets
2537 # First identify rpaths
2538 bin_install_rpaths = []
2539 lib_install_rpaths = []
2540 mod_install_rpaths = []
2543 # Don't add rpaths on darwin for now - as long as only absolute references to
2544 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2545 # their final destination.
2546 if host_system != 'darwin'
2547 # Add absolute path to libdir to rpath. This ensures installed binaries /
2548 # libraries find our libraries (mainly libpq).
2549 bin_install_rpaths += dir_prefix / dir_lib
2550 lib_install_rpaths += dir_prefix / dir_lib
2551 mod_install_rpaths += dir_prefix / dir_lib
2553 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2555 # Not needed on darwin even if we use relative rpaths for our own libraries,
2556 # as the install_name of libraries in extra_lib_dirs will point to their
2558 bin_install_rpaths += postgres_lib_d
2559 lib_install_rpaths += postgres_lib_d
2560 mod_install_rpaths += postgres_lib_d
2564 # Define arguments for default targets
2566 default_target_args = {
2567 'implicit_include_directories': false,
2571 default_lib_args = default_target_args + {
2573 'install_rpath': ':'.join(lib_install_rpaths),
2576 internal_lib_args = default_lib_args + {
2577 'build_by_default': false,
2581 default_mod_args = default_lib_args + {
2583 'install_dir': dir_lib_pkg,
2584 'install_rpath': ':'.join(mod_install_rpaths),
2587 default_bin_args = default_target_args + {
2588 'install_dir': dir_bin,
2589 'install_rpath': ':'.join(bin_install_rpaths),
2594 # Helper for exporting a limited number of symbols
2595 gen_export_kwargs = {
2596 'input': 'exports.txt',
2597 'output': '@BASENAME@.'+export_file_suffix,
2598 'command': [perl, files('src/tools/gen_export.pl'),
2599 '--format', export_file_format,
2600 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2601 'build_by_default': false,
2608 ### windows resources related stuff
2611 if host_system == 'windows'
2612 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2613 win32ver_rc = files('src/port/win32ver.rc')
2614 rcgen = find_program('src/tools/rcgen', native: true)
2617 '--srcdir', '@SOURCE_DIR@',
2618 '--builddir', meson.build_root(),
2619 '--rcout', '@OUTPUT0@',
2620 '--out', '@OUTPUT1@',
2621 '--input', '@INPUT@',
2625 if cc.get_argument_syntax() == 'msvc'
2626 rc = find_program('rc', required: true)
2627 rcgen_base_args += ['--rc', rc.path()]
2628 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2630 windres = find_program('windres', required: true)
2631 rcgen_base_args += ['--windres', windres.path()]
2632 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2635 # msbuild backend doesn't support this atm
2636 if meson.backend() == 'ninja'
2637 rcgen_base_args += ['--depfile', '@DEPFILE@']
2640 rcgen_bin_args = rcgen_base_args + [
2641 '--VFT_TYPE', 'VFT_APP',
2642 '--FILEENDING', 'exe',
2646 rcgen_lib_args = rcgen_base_args + [
2647 '--VFT_TYPE', 'VFT_DLL',
2648 '--FILEENDING', 'dll',
2651 rc_bin_gen = generator(rcgen,
2652 depfile: '@BASENAME@.d',
2653 arguments: rcgen_bin_args,
2654 output: rcgen_outputs,
2657 rc_lib_gen = generator(rcgen,
2658 depfile: '@BASENAME@.d',
2659 arguments: rcgen_lib_args,
2660 output: rcgen_outputs,
2666 # headers that the whole build tree depends on
2667 generated_headers = []
2668 # headers that the backend build depends on
2669 generated_backend_headers = []
2670 # configure_files() output, needs a way of converting to file names
2671 configure_files = []
2673 # generated files that might conflict with a partial in-tree autoconf build
2674 generated_sources = []
2675 # same, for paths that differ between autoconf / meson builds
2676 # elements are [dir, [files]]
2677 generated_sources_ac = {}
2680 # First visit src/include - all targets creating headers are defined
2681 # within. That makes it easy to add the necessary dependencies for the
2682 # subsequent build steps.
2684 subdir('src/include')
2688 # Then through src/port and src/common, as most other things depend on them
2690 frontend_port_code = declare_dependency(
2691 compile_args: ['-DFRONTEND'],
2692 include_directories: [postgres_inc],
2693 dependencies: os_deps,
2696 backend_port_code = declare_dependency(
2697 compile_args: ['-DBUILDING_DLL'],
2698 include_directories: [postgres_inc],
2699 sources: [errcodes], # errcodes.h is needed due to use of ereport
2700 dependencies: os_deps,
2705 frontend_common_code = declare_dependency(
2706 compile_args: ['-DFRONTEND'],
2707 include_directories: [postgres_inc],
2708 sources: generated_headers,
2709 dependencies: [os_deps, zlib, zstd],
2712 backend_common_code = declare_dependency(
2713 compile_args: ['-DBUILDING_DLL'],
2714 include_directories: [postgres_inc],
2715 sources: generated_headers,
2716 dependencies: [os_deps, zlib, zstd],
2719 subdir('src/common')
2721 # all shared libraries should depend on shlib_code
2722 shlib_code = declare_dependency(
2723 link_args: ldflags_sl,
2726 # all static libraries not part of the backend should depend on this
2727 frontend_stlib_code = declare_dependency(
2728 include_directories: [postgres_inc],
2729 link_with: [common_static, pgport_static],
2730 sources: generated_headers,
2731 dependencies: [os_deps, libintl],
2734 # all shared libraries not part of the backend should depend on this
2735 frontend_shlib_code = declare_dependency(
2736 include_directories: [postgres_inc],
2737 link_with: [common_shlib, pgport_shlib],
2738 sources: generated_headers,
2739 dependencies: [shlib_code, os_deps, libintl],
2742 # Dependencies both for static and shared libpq
2752 subdir('src/interfaces/libpq')
2753 # fe_utils depends on libpq
2754 subdir('src/fe_utils')
2756 # for frontend binaries
2757 frontend_code = declare_dependency(
2758 include_directories: [postgres_inc],
2759 link_with: [fe_utils, common_static, pgport_static],
2760 sources: generated_headers,
2761 dependencies: [os_deps, libintl],
2764 backend_both_deps += [
2781 backend_mod_deps = backend_both_deps + os_deps
2783 backend_code = declare_dependency(
2784 compile_args: ['-DBUILDING_DLL'],
2785 include_directories: [postgres_inc],
2786 link_args: ldflags_be,
2788 sources: generated_headers + generated_backend_headers,
2789 dependencies: os_deps + backend_both_deps + backend_deps,
2792 # src/backend/meson.build defines backend_mod_code used for extension
2796 # Then through the main sources. That way contrib can have dependencies on
2797 # main sources. Note that this explicitly doesn't enter src/test, right now a
2798 # few regression tests depend on contrib files.
2805 subdir('src/interfaces/libpq/test')
2806 subdir('src/interfaces/ecpg/test')
2808 subdir('doc/src/sgml')
2810 generated_sources_ac += {'': ['GNUmakefile']}
2813 # If there are any files in the source directory that we also generate in the
2814 # build directory, they might get preferred over the newly generated files,
2815 # e.g. because of a #include "file", which always will search in the current
2817 message('checking for file conflicts between source and build directory')
2818 conflicting_files = []
2819 potentially_conflicting_files_t = []
2820 potentially_conflicting_files_t += generated_headers
2821 potentially_conflicting_files_t += generated_backend_headers
2822 potentially_conflicting_files_t += generated_backend_sources
2823 potentially_conflicting_files_t += generated_sources
2825 potentially_conflicting_files = []
2827 # convert all sources of potentially conflicting files into uniform shape
2828 foreach t : potentially_conflicting_files_t
2829 potentially_conflicting_files += t.full_path()
2831 foreach t : configure_files
2833 potentially_conflicting_files += meson.current_build_dir() / t
2835 foreach sub, fnames : generated_sources_ac
2836 sub = meson.build_root() / sub
2837 foreach fname : fnames
2838 potentially_conflicting_files += sub / fname
2842 # find and report conflicting files
2843 foreach build_path : potentially_conflicting_files
2844 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2845 # str.replace is in 0.56
2846 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2847 if fs.exists(src_path) or fs.is_symlink(src_path)
2848 conflicting_files += src_path
2851 # XXX: Perhaps we should generate a file that would clean these up? The list
2853 if conflicting_files.length() > 0
2854 errmsg_cleanup = '''
2855 Conflicting files in source directory:
2858 The conflicting files need to be removed, either by removing the files listed
2859 above, or by running configure and then make maintainer-clean.
2861 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2862 error(errmsg_nonclean_base.format(errmsg_cleanup))
2867 ###############################################################
2869 ###############################################################
2871 # DESTDIR for the installation we'll run tests in
2872 test_install_destdir = meson.build_root() / 'tmp_install/'
2874 # DESTDIR + prefix appropriately munged
2875 if build_system != 'windows'
2876 # On unixoid systems this is trivial, we just prepend the destdir
2877 assert(dir_prefix.startswith('/')) # enforced by meson
2878 test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
2880 # drives, drive-relative paths, etc make this complicated on windows, call
2881 # meson's logic for it
2883 meson_bin, meson_args, 'runpython', '-c',
2884 'import sys; from mesonbuild.scripts import destdir_join; print(destdir_join(sys.argv[4], sys.argv[5]))',
2885 test_install_destdir, dir_prefix]
2886 test_install_location = run_command(command, check: true).stdout().strip()
2889 meson_install_args = meson_args + ['install'] + {
2890 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
2895 meson_bin, args: meson_install_args ,
2896 env: {'DESTDIR':test_install_destdir},
2902 test_result_dir = meson.build_root() / 'testrun'
2905 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
2906 # inevitable conflicts from running tests in parallel, hackishly assign
2907 # different ports for different tests.
2911 test_env = environment()
2913 temp_install_bindir = test_install_location / get_option('bindir')
2914 test_env.set('PG_REGRESS', pg_regress.full_path())
2915 test_env.set('REGRESS_SHLIB', regress_module.full_path())
2917 # Test suites that are not safe by default but can be run if selected
2918 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
2919 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
2920 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
2922 # Add the temporary installation to the library search path on platforms where
2923 # that works (everything but windows, basically). On windows everything
2924 # library-like gets installed into bindir, solving that issue.
2925 if library_path_var != ''
2926 test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
2931 ###############################################################
2933 ###############################################################
2935 # When using a meson version understanding exclude_suites, define a
2936 # 'tmp_install' test setup (the default) that excludes tests running against a
2937 # pre-existing install and a 'running' setup that conflicts with creation of
2938 # the temporary installation and tap tests (which don't support running
2939 # against a running server).
2943 if meson.version().version_compare('>=0.57')
2946 runningcheck = false
2949 testwrap = files('src/tools/testwrap')
2951 foreach test_dir : tests
2954 '--basedir', meson.build_root(),
2955 '--srcdir', test_dir['sd'],
2958 foreach kind, v : test_dir
2959 if kind in ['sd', 'bd', 'name']
2965 if kind in ['regress', 'isolation', 'ecpg']
2966 if kind == 'regress'
2968 fallback_dbname = 'regression_@0@'
2969 elif kind == 'isolation'
2970 runner = pg_isolation_regress
2971 fallback_dbname = 'isolation_regression_@0@'
2973 runner = pg_regress_ecpg
2974 fallback_dbname = 'ecpg_regression_@0@'
2977 test_group = test_dir['name']
2978 test_group_running = test_dir['name'] + '-running'
2980 test_output = test_result_dir / test_group / kind
2981 test_output_running = test_result_dir / test_group_running/ kind
2983 # Unless specified by the test, choose a non-conflicting database name,
2984 # to avoid conflicts when running against existing server.
2985 dbname = t.get('dbname',
2986 fallback_dbname.format(test_dir['name']))
2988 test_command_base = [
2990 '--inputdir', t.get('inputdir', test_dir['sd']),
2991 '--expecteddir', t.get('expecteddir', test_dir['sd']),
2993 '--dlpath', test_dir['bd'],
2994 '--max-concurrent-tests=20',
2996 ] + t.get('regress_args', [])
2999 if t.has_key('schedule')
3000 test_selection += ['--schedule', t['schedule'],]
3003 if kind == 'isolation'
3004 test_selection += t.get('specs', [])
3006 test_selection += t.get('sql', [])
3010 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3015 'depends': test_deps + t.get('deps', []),
3017 } + t.get('test_kwargs', {})
3019 test(test_group / kind,
3023 '--testgroup', test_group,
3027 '--outputdir', test_output,
3028 '--temp-instance', test_output / 'tmp_check',
3029 '--port', testport.to_string(),
3033 kwargs: test_kwargs,
3035 install_suites += test_group
3037 # some tests can't support running against running DB
3038 if runningcheck and t.get('runningcheck', true)
3039 test(test_group_running / kind,
3043 '--testgroup', test_group_running,
3047 '--outputdir', test_output_running,
3050 is_parallel: t.get('runningcheck-parallel', true),
3051 suite: test_group_running,
3052 kwargs: test_kwargs,
3054 running_suites += test_group_running
3059 if not tap_tests_enabled
3065 '-I', meson.source_root() / 'src/test/perl',
3066 '-I', test_dir['sd'],
3069 # Add temporary install, the build directory for non-installed binaries and
3070 # also test/ for non-installed test binaries built separately.
3072 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3074 foreach name, value : t.get('env', {})
3075 env.set(name, value)
3078 test_group = test_dir['name']
3081 'suite': test_group,
3083 'depends': test_deps + t.get('deps', []),
3085 } + t.get('test_kwargs', {})
3087 foreach onetap : t['tests']
3088 # Make tap test names prettier, remove t/ and .pl
3090 if onetap_p.startswith('t/')
3091 onetap_p = onetap.split('t/')[1]
3093 if onetap_p.endswith('.pl')
3094 onetap_p = fs.stem(onetap_p)
3097 test(test_dir['name'] / onetap_p,
3099 kwargs: test_kwargs,
3100 args: testwrap_base + [
3101 '--testgroup', test_dir['name'],
3102 '--testname', onetap_p,
3104 test_dir['sd'] / onetap,
3108 install_suites += test_group
3110 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3113 endforeach # kinds of tests
3115 endforeach # directories with tests
3117 # repeat condition so meson realizes version dependency
3118 if meson.version().version_compare('>=0.57')
3119 add_test_setup('tmp_install',
3121 exclude_suites: running_suites)
3122 add_test_setup('running',
3123 exclude_suites: ['setup'] + install_suites)
3127 ###############################################################
3129 ###############################################################
3131 alias_target('backend', backend_targets)
3132 alias_target('bin', bin_targets + [libpq_st])
3133 alias_target('pl', pl_targets)
3134 alias_target('contrib', contrib_targets)
3135 alias_target('testprep', testprep_targets)
3139 ###############################################################
3140 # The End, The End, My Friend
3141 ###############################################################
3143 if meson.version().version_compare('>=0.57')
3147 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3148 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3149 'segment size': get_option('segsize_blocks') != 0 ?
3150 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3151 '@0@ GB'.format(get_option('segsize')),
3153 section: 'Data layout',
3158 'host system': '@0@ @1@'.format(host_system, host_cpu),
3159 'build system': '@0@ @1@'.format(build_machine.system(),
3160 build_machine.cpu_family()),
3167 'linker': '@0@'.format(cc.get_linker_id()),
3168 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3170 section: 'Compiler',
3175 'CPP FLAGS': ' '.join(cppflags),
3176 'C FLAGS, functional': ' '.join(cflags),
3177 'C FLAGS, warnings': ' '.join(cflags_warn),
3178 'C FLAGS, modules': ' '.join(cflags_mod),
3179 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3180 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3182 section: 'Compiler Flags',
3188 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3190 section: 'Compiler',
3195 'C++ FLAGS, functional': ' '.join(cxxflags),
3196 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3197 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3199 section: 'Compiler Flags',
3205 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3208 section: 'Programs',
3214 'bsd_auth': bsd_auth,
3225 'plpython': python3_dep,
3227 'readline': readline,
3235 section: 'External libraries',