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)
347 bison_version_c = run_command(bison, '--version', check: true)
348 # bison version string helpfully is something like
349 # >>bison (GNU bison) 3.8.1<<
350 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
351 if bison_version.version_compare('>=3.0')
352 bison_flags += ['-Wno-deprecated']
355 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
357 'output': ['@BASENAME@.c', '@BASENAME@.h'],
358 'command': bison_cmd,
362 flex_wrapper = files('src/tools/pgflex')
363 flex_cmd = [python, flex_wrapper,
364 '--builddir', '@BUILD_ROOT@',
365 '--srcdir', '@SOURCE_ROOT@',
366 '--privatedir', '@PRIVATE_DIR@',
367 '--flex', flex, '--perl', perl,
368 '-i', '@INPUT@', '-o', '@OUTPUT0@',
371 wget = find_program('wget', required: false, native: true)
372 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
374 install_files = files('src/tools/install_files')
378 ###############################################################
379 # Path to meson (for tests etc)
380 ###############################################################
382 # NB: this should really be part of meson, see
383 # https://github.com/mesonbuild/meson/issues/8511
384 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
386 if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
387 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
388 meson_binpath_r.returncode(),
389 meson_binpath_r.stdout(),
390 meson_binpath_r.stderr()))
393 meson_binpath_s = meson_binpath_r.stdout().split('\n')
394 meson_binpath_len = meson_binpath_s.length()
396 if meson_binpath_len < 1
397 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
404 foreach e : meson_binpath_s
415 if meson_impl not in ['muon', 'meson']
416 error('unknown meson implementation "@0@"'.format(meson_impl))
419 meson_bin = find_program(meson_binpath, native: true)
423 ###############################################################
425 ###############################################################
427 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
429 blocksize = get_option('blocksize').to_int() * 1024
431 if get_option('segsize_blocks') != 0
432 if get_option('segsize') != 1
433 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
436 segsize = get_option('segsize_blocks')
438 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
441 cdata.set('BLCKSZ', blocksize, description:
442 '''Size of a disk block --- this also limits the size of a tuple. You can set
443 it bigger if you need bigger tuples (although TOAST should reduce the need
444 to have large tuples, since fields can be spread across multiple tuples).
445 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
446 currently 2^15 (32768). This is determined by the 15-bit widths of the
447 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
448 Changing BLCKSZ requires an initdb.''')
450 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
451 cdata.set('RELSEG_SIZE', segsize)
452 cdata.set('DEF_PGPORT', get_option('pgport'))
453 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
454 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
455 if get_option('system_tzdata') != ''
456 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
461 ###############################################################
463 ###############################################################
465 # These are set by the equivalent --xxxdir configure options. We
466 # append "postgresql" to some of them, if the string does not already
467 # contain "pgsql" or "postgres", in order to avoid directory clutter.
471 dir_prefix = get_option('prefix')
473 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
475 dir_bin = get_option('bindir')
477 dir_data = get_option('datadir')
478 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
479 dir_data = dir_data / pkg
482 dir_sysconf = get_option('sysconfdir')
483 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
484 dir_sysconf = dir_sysconf / pkg
487 dir_lib = get_option('libdir')
489 dir_lib_pkg = dir_lib
490 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
491 dir_lib_pkg = dir_lib_pkg / pkg
494 dir_pgxs = dir_lib_pkg / 'pgxs'
496 dir_include = get_option('includedir')
498 dir_include_pkg = dir_include
499 dir_include_pkg_rel = ''
500 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
501 dir_include_pkg = dir_include_pkg / pkg
502 dir_include_pkg_rel = pkg
505 dir_man = get_option('mandir')
507 # FIXME: These used to be separately configurable - worth adding?
508 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
509 dir_doc_html = dir_doc / 'html'
511 dir_locale = get_option('localedir')
515 dir_bitcode = dir_lib_pkg / 'bitcode'
516 dir_include_internal = dir_include_pkg / 'internal'
517 dir_include_server = dir_include_pkg / 'server'
518 dir_include_extension = dir_include_server / 'extension'
519 dir_data_extension = dir_data / 'extension'
523 ###############################################################
524 # Search paths, preparation for compiler tests
526 # NB: Arguments added later are not automatically used for subsequent
527 # configuration-time checks (so they are more isolated). If they should be
528 # used, they need to be added to test_c_args as well.
529 ###############################################################
531 postgres_inc = [include_directories(postgres_inc_d)]
532 test_lib_d = postgres_lib_d
533 test_c_args = cppflags + cflags
537 ###############################################################
539 ###############################################################
541 bsd_authopt = get_option('bsd_auth')
542 bsd_auth = not_found_dep
543 if cc.check_header('bsd_auth.h', required: bsd_authopt,
544 args: test_c_args, include_directories: postgres_inc)
545 cdata.set('USE_BSD_AUTH', 1)
546 bsd_auth = declare_dependency()
551 ###############################################################
554 # For now don't search for DNSServiceRegister in a library - only Apple's
555 # Bonjour implementation, which is always linked, works.
556 ###############################################################
558 bonjouropt = get_option('bonjour')
559 bonjour = dependency('', required : false)
560 if cc.check_header('dns_sd.h', required: bonjouropt,
561 args: test_c_args, include_directories: postgres_inc) and \
562 cc.has_function('DNSServiceRegister',
563 args: test_c_args, include_directories: postgres_inc)
564 cdata.set('USE_BONJOUR', 1)
565 bonjour = declare_dependency()
570 ###############################################################
572 ###############################################################
574 gssapiopt = get_option('gssapi')
577 if not gssapiopt.disabled()
578 gssapi = dependency('krb5-gssapi', required: gssapiopt)
579 have_gssapi = gssapi.found()
582 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
583 args: test_c_args, include_directories: postgres_inc)
584 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
585 elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
586 cdata.set('HAVE_GSSAPI_H', 1)
592 elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
593 args: test_c_args, include_directories: postgres_inc)
594 cdata.set('ENABLE_GSS', 1)
596 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
597 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
598 elif gssapiopt.enabled()
599 error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
605 gssapi = not_found_dep
610 ###############################################################
612 ###############################################################
614 ldapopt = get_option('ldap')
615 if ldapopt.disabled()
617 ldap_r = not_found_dep
618 elif host_system == 'windows'
619 ldap = cc.find_library('wldap32', required: ldapopt)
622 # macos framework dependency is buggy for ldap (one can argue whether it's
623 # Apple's or meson's fault), leading to an endless recursion with ldap.h
624 # including itself. See https://github.com/mesonbuild/meson/issues/10002
625 # Luckily we only need pkg-config support, so the workaround isn't
627 ldap = dependency('ldap', method: 'pkg-config', required: false)
630 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
633 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
634 has_headers: 'ldap.h', header_include_directories: postgres_inc)
636 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
637 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
638 # library from a separate OpenLDAP installation). The most reliable
639 # way to check that is to check for a function introduced in 2.5.
641 # don't have ldap, we shouldn't check for ldap_r
642 elif cc.has_function('ldap_verify_credentials',
643 dependencies: ldap, args: test_c_args)
644 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
647 # Use ldap_r for FE if available, else assume ldap is thread-safe.
648 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
649 has_headers: 'ldap.h', header_include_directories: postgres_inc)
650 if not ldap_r.found()
653 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
654 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
657 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
658 # process. Check for OpenLDAP versions known not to tolerate doing so;
659 # assume non-OpenLDAP implementations are safe. The dblink test suite
660 # exercises the hazardous interaction directly.
661 compat_test_code = '''
663 #if !defined(LDAP_VENDOR_VERSION) || \
664 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
665 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
669 if not cc.compiles(compat_test_code,
670 name: 'LDAP implementation compatible',
671 dependencies: ldap, args: test_c_args)
673 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
674 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
675 *** also uses LDAP will crash on exit.''')
680 # XXX: this shouldn't be tested in the windows case, but should be tested in
681 # the dependency() success case
682 if ldap.found() and cc.has_function('ldap_initialize',
683 dependencies: ldap, args: test_c_args)
684 cdata.set('HAVE_LDAP_INITIALIZE', 1)
689 assert(ldap_r.found())
690 cdata.set('USE_LDAP', 1)
692 assert(not ldap_r.found())
697 ###############################################################
699 ###############################################################
701 llvmopt = get_option('llvm')
702 if not llvmopt.disabled()
703 add_languages('cpp', required: true, native: false)
704 llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
708 cdata.set('USE_LLVM', 1)
710 cpp = meson.get_compiler('cpp')
712 llvm_binpath = llvm.get_variable(configtool: 'bindir')
714 ccache = find_program('ccache', native: true, required: false)
715 clang = find_program(llvm_binpath / 'clang', required: true)
723 ###############################################################
725 ###############################################################
727 icuopt = get_option('icu')
728 if not icuopt.disabled()
729 icu = dependency('icu-uc', required: icuopt.enabled())
730 icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
733 cdata.set('USE_ICU', 1)
738 icu_i18n = not_found_dep
743 ###############################################################
745 ###############################################################
747 libxmlopt = get_option('libxml')
748 if not libxmlopt.disabled()
749 libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
752 cdata.set('USE_LIBXML', 1)
755 libxml = not_found_dep
760 ###############################################################
762 ###############################################################
764 libxsltopt = get_option('libxslt')
765 if not libxsltopt.disabled()
766 libxslt = dependency('libxslt', required: libxsltopt)
769 cdata.set('USE_LIBXSLT', 1)
772 libxslt = not_found_dep
777 ###############################################################
779 ###############################################################
781 lz4opt = get_option('lz4')
782 if not lz4opt.disabled()
783 lz4 = dependency('liblz4', required: lz4opt)
786 cdata.set('USE_LZ4', 1)
787 cdata.set('HAVE_LIBLZ4', 1)
796 ###############################################################
797 # Library: Tcl (for pltcl)
799 # NB: tclConfig.sh is used in autoconf build for getting
800 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
801 # variables. For now we have not seen a need to copy
802 # that behaviour to the meson build.
803 ###############################################################
805 tclopt = get_option('pltcl')
806 tcl_version = get_option('tcl_version')
807 tcl_dep = not_found_dep
808 if not tclopt.disabled()
811 tcl_dep = dependency(tcl_version, required: false)
813 if not tcl_dep.found()
814 tcl_dep = cc.find_library(tcl_version,
819 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
820 tcl_dep = not_found_dep
826 ###############################################################
828 ###############################################################
830 pamopt = get_option('pam')
831 if not pamopt.disabled()
832 pam = dependency('pam', required: false)
835 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
839 pam_header_found = false
841 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
842 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
843 args: test_c_args, include_directories: postgres_inc)
844 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
845 pam_header_found = true
846 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
847 args: test_c_args, include_directories: postgres_inc)
848 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
849 pam_header_found = true
853 cdata.set('USE_PAM', 1)
864 ###############################################################
865 # Library: Perl (for plperl)
866 ###############################################################
868 perlopt = get_option('plperl')
869 perl_dep = not_found_dep
870 if not perlopt.disabled()
873 # First verify that perl has the necessary dependencies installed
874 perl_mods = run_command(
876 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
879 if perl_mods.returncode() != 0
880 perl_may_work = false
881 perl_msg = 'perl installation does not have the required modules'
884 # Then inquire perl about its configuration
886 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
887 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
888 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
889 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
890 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
892 perl_inc_dir = '@0@/CORE'.format(archlibexp)
894 if perlversion.version_compare('< 5.14')
895 perl_may_work = false
896 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
897 elif useshrplib != 'true'
898 perl_may_work = false
899 perl_msg = 'need a shared perl'
904 # On most platforms, archlibexp is also where the Perl include files live ...
905 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
906 # ... but on newer macOS versions, we must use -iwithsysroot to look
908 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
909 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
910 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
913 # check compiler finds header
914 if not cc.has_header('perl.h', required: false,
915 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
916 perl_may_work = false
917 perl_msg = 'missing perl.h'
922 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
924 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
925 foreach flag : perl_ccflags_r.split(' ')
926 if flag.startswith('-D') and \
927 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
932 if host_system == 'windows'
933 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
935 if cc.get_id() == 'msvc'
936 # prevent binary mismatch between MSVC built plperl and Strawberry or
937 # msys ucrt perl libraries
938 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
942 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
943 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
945 # We are after Embed's ldopts, but without the subset mentioned in
946 # Config's ccdlflags and ldflags. (Those are the choices of those who
947 # built the Perl installation, which are not necessarily appropriate
948 # for building PostgreSQL.)
949 ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
950 undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
951 undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
954 foreach ldopt : ldopts.split(' ')
955 if ldopt == '' or ldopt in undesired
959 perl_ldopts += ldopt.strip('"')
962 message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
963 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
965 perl_dep_int = declare_dependency(
966 compile_args: perl_ccflags,
967 link_args: perl_ldopts,
968 version: perlversion,
971 # While we're at it, check that we can link to libperl.
972 # On most platforms, if perl.h is there then libperl.so will be too, but
973 # at this writing Debian packages them separately.
977 #define __inline__ inline
985 if not cc.links(perl_link_test, name: 'libperl',
986 args: test_c_args + perl_ccflags + perl_ldopts,
987 include_directories: postgres_inc)
988 perl_may_work = false
989 perl_msg = 'missing libperl'
992 endif # perl_may_work
995 perl_dep = perl_dep_int
998 error('dependency plperl failed: @0@'.format(perl_msg))
1000 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1007 ###############################################################
1008 # Library: Python (for plpython)
1009 ###############################################################
1011 pyopt = get_option('plpython')
1012 if not pyopt.disabled()
1013 pm = import('python')
1014 python3_inst = pm.find_installation(required: pyopt.enabled())
1015 python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
1016 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
1017 python3_dep = not_found_dep
1020 python3_dep = not_found_dep
1025 ###############################################################
1027 ###############################################################
1029 if not get_option('readline').disabled()
1030 libedit_preferred = get_option('libedit_preferred')
1031 # Set the order of readline dependencies
1032 check_readline_deps = libedit_preferred ? \
1033 ['libedit', 'readline'] : ['readline', 'libedit']
1035 foreach readline_dep : check_readline_deps
1036 readline = dependency(readline_dep, required: false)
1037 if not readline.found()
1038 readline = cc.find_library(readline_dep,
1039 required: get_option('readline').enabled(),
1048 cdata.set('HAVE_LIBREADLINE', 1)
1051 'header_prefix': 'editline/',
1052 'flag_prefix': 'EDITLINE_',
1055 'header_prefix': 'readline/',
1056 'flag_prefix': 'READLINE_',
1059 'header_prefix': '',
1063 # Set the order of prefixes
1064 prefixes = libedit_preferred ? \
1065 [editline_prefix, default_prefix, readline_prefix] : \
1066 [readline_prefix, default_prefix, editline_prefix]
1068 at_least_one_header_found = false
1069 foreach header : ['history', 'readline']
1071 foreach prefix : prefixes
1072 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1073 # Check history.h and readline.h
1074 if not is_found and cc.has_header(header_file,
1075 args: test_c_args, include_directories: postgres_inc,
1076 dependencies: [readline], required: false)
1077 if header == 'readline'
1078 readline_h = header_file
1080 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1082 at_least_one_header_found = true
1087 if not at_least_one_header_found
1088 error('''readline header not found
1089 If you have @0@ already installed, see meson-log/meson-log.txt for details on the
1090 failure. It is possible the compiler isn't looking in the proper directory.
1091 Use -Dreadline=false to disable readline support.'''.format(readline_dep))
1096 'history_truncate_file',
1097 'rl_completion_matches',
1098 'rl_filename_completion_function',
1099 'rl_reset_screen_size',
1103 foreach func : check_funcs
1104 found = cc.has_function(func, dependencies: [readline],
1105 args: test_c_args, include_directories: postgres_inc)
1106 cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
1110 'rl_completion_suppress_quote',
1111 'rl_filename_quote_characters',
1112 'rl_filename_quoting_function',
1115 foreach var : check_vars
1116 cdata.set('HAVE_'+var.to_upper(),
1117 cc.has_header_symbol(readline_h, var,
1118 args: test_c_args, include_directories: postgres_inc,
1119 prefix: '#include <stdio.h>',
1120 dependencies: [readline]) ? 1 : false)
1123 # If found via cc.find_library() ensure headers are found when using the
1124 # dependency. On meson < 0.57 one cannot do compiler checks using the
1125 # dependency returned by declare_dependency(), so we can't do this above.
1126 if readline.type_name() == 'library'
1127 readline = declare_dependency(dependencies: readline,
1128 include_directories: postgres_inc)
1131 # On windows with mingw readline requires auto-import to successfully
1132 # link, as the headers don't use declspec(dllimport)
1133 if host_system == 'windows' and cc.get_id() != 'msvc'
1134 readline = declare_dependency(dependencies: readline,
1135 link_args: '-Wl,--enable-auto-import')
1139 # XXX: Figure out whether to implement mingw warning equivalent
1141 readline = not_found_dep
1146 ###############################################################
1148 ###############################################################
1150 selinux = not_found_dep
1151 selinuxopt = get_option('selinux')
1152 if meson.version().version_compare('>=0.59')
1153 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1155 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1156 cdata.set('HAVE_LIBSELINUX',
1157 selinux.found() ? 1 : false)
1161 ###############################################################
1163 ###############################################################
1165 systemd = not_found_dep
1166 systemdopt = get_option('systemd')
1167 if meson.version().version_compare('>=0.59')
1168 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1170 systemd = dependency('libsystemd', required: systemdopt)
1171 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1175 ###############################################################
1177 ###############################################################
1180 ssl_library = 'none'
1181 sslopt = get_option('ssl')
1183 if sslopt == 'auto' and auto_features.disabled()
1187 if sslopt in ['auto', 'openssl']
1188 openssl_required = (sslopt == 'openssl')
1190 # Try to find openssl via pkg-config et al, if that doesn't work
1191 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1192 # the library names that we know about.
1194 # via pkg-config et al
1195 ssl = dependency('openssl', required: false)
1196 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1197 # we pass cc.find_library() results if necessary
1200 # via library + headers
1202 ssl_lib = cc.find_library('ssl',
1204 header_include_directories: postgres_inc,
1205 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1206 required: openssl_required)
1207 crypto_lib = cc.find_library('crypto',
1209 required: openssl_required)
1210 if ssl_lib.found() and crypto_lib.found()
1211 ssl_int = [ssl_lib, crypto_lib]
1212 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1214 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1215 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1223 ['CRYPTO_new_ex_data', {'required': true}],
1224 ['SSL_new', {'required': true}],
1226 # Functions introduced in OpenSSL 1.0.2.
1227 ['X509_get_signature_nid'],
1228 ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1230 # Functions introduced in OpenSSL 1.1.0. We used to check for
1231 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1232 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1233 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1235 ['OPENSSL_init_ssl'],
1238 ['ASN1_STRING_get0_data'],
1242 # OpenSSL versions before 1.1.0 required setting callback functions, for
1243 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1244 # function was removed.
1247 # Function introduced in OpenSSL 1.1.1
1248 ['X509_get_signature_info'],
1251 are_openssl_funcs_complete = true
1252 foreach c : check_funcs
1254 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1255 required = c.get(1, {}).get('required', false)
1256 if required and not val
1257 are_openssl_funcs_complete = false
1259 error('openssl function @0@ is required'.format(func))
1263 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1267 if are_openssl_funcs_complete
1268 cdata.set('USE_OPENSSL', 1,
1269 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1270 cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1271 description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
1272 ssl_library = 'openssl'
1279 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1280 error('no SSL library found')
1285 ###############################################################
1287 ###############################################################
1289 uuidopt = get_option('uuid')
1290 if uuidopt != 'none'
1291 uuidname = uuidopt.to_upper()
1292 if uuidopt == 'e2fs'
1293 uuid = dependency('uuid', required: true)
1294 uuidfunc = 'uuid_generate'
1295 uuidheader = 'uuid/uuid.h'
1296 elif uuidopt == 'bsd'
1297 # libc should have uuid function
1298 uuid = declare_dependency()
1299 uuidfunc = 'uuid_to_string'
1300 uuidheader = 'uuid.h'
1301 elif uuidopt == 'ossp'
1302 uuid = dependency('ossp-uuid', required: true)
1303 uuidfunc = 'uuid_export'
1304 uuidheader = 'uuid.h'
1309 if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1310 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1312 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1314 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1315 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1317 uuid = not_found_dep
1322 ###############################################################
1324 ###############################################################
1326 zlibopt = get_option('zlib')
1327 zlib = not_found_dep
1328 if not zlibopt.disabled()
1329 zlib_t = dependency('zlib', required: zlibopt)
1331 if zlib_t.type_name() == 'internal'
1332 # if fallback was used, we don't need to test if headers are present (they
1333 # aren't built yet, so we can't test)
1335 elif not zlib_t.found()
1336 warning('did not find zlib')
1337 elif not cc.has_header('zlib.h',
1338 args: test_c_args, include_directories: postgres_inc,
1339 dependencies: [zlib_t], required: zlibopt.enabled())
1340 warning('zlib header not found')
1341 elif not cc.has_type('z_streamp',
1342 dependencies: [zlib_t], prefix: '#include <zlib.h>',
1343 args: test_c_args, include_directories: postgres_inc)
1344 if zlibopt.enabled()
1345 error('zlib version is too old')
1347 warning('zlib version is too old')
1354 cdata.set('HAVE_LIBZ', 1)
1360 ###############################################################
1361 # Library: tap test dependencies
1362 ###############################################################
1364 # Check whether tap tests are enabled or not
1365 tap_tests_enabled = false
1366 tapopt = get_option('tap_tests')
1367 if not tapopt.disabled()
1368 # Checking for perl modules for tap tests
1369 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1370 if perl_ipc_run_check.returncode() != 0
1371 message(perl_ipc_run_check.stderr().strip())
1373 error('Additional Perl modules are required to run TAP tests.')
1375 warning('Additional Perl modules are required to run TAP tests.')
1378 tap_tests_enabled = true
1384 ###############################################################
1386 ###############################################################
1388 zstdopt = get_option('zstd')
1389 if not zstdopt.disabled()
1390 zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1393 cdata.set('USE_ZSTD', 1)
1394 cdata.set('HAVE_LIBZSTD', 1)
1398 zstd = not_found_dep
1403 ###############################################################
1405 ###############################################################
1407 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1408 # unnecessarily, because we optionally rely on newer features.
1410 #include <stdbool.h>
1411 #include <complex.h>
1413 #include <inttypes.h>
1415 struct named_init_test {
1420 extern void structfunc(struct named_init_test);
1422 int main(int argc, char **argv)
1424 struct named_init_test nit = {
1429 for (int loop_var = 0; loop_var < 3; loop_var++)
1434 structfunc((struct named_init_test){1, 0});
1440 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1441 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1442 args: test_c_args + ['-std=c99'])
1443 test_c_args += '-std=c99'
1444 cflags += '-std=c99'
1446 error('C compiler does not support C99')
1450 sizeof_long = cc.sizeof('long', args: test_c_args)
1451 cdata.set('SIZEOF_LONG', sizeof_long)
1453 cdata.set('HAVE_LONG_INT_64', 1)
1454 cdata.set('PG_INT64_TYPE', 'long int')
1455 cdata.set_quoted('INT64_MODIFIER', 'l')
1456 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1457 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1458 cdata.set('PG_INT64_TYPE', 'long long int')
1459 cdata.set_quoted('INT64_MODIFIER', 'll')
1461 error('do not know how to get a 64bit int')
1464 if host_machine.endian() == 'big'
1465 cdata.set('WORDS_BIGENDIAN', 1)
1468 alignof_types = ['short', 'int', 'long', 'double']
1470 foreach t : alignof_types
1471 align = cc.alignment(t, args: test_c_args)
1475 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1477 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1479 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1480 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1483 # Check if __int128 is a working 128 bit integer type, and if so
1484 # define PG_INT128_TYPE to that typename.
1486 # This currently only detects a GCC/clang extension, but support for other
1487 # environments may be added in the future.
1489 # For the moment we only test for support for 128bit math; support for
1490 # 128bit literals and snprintf is not required.
1493 * We don't actually run this test, just link it to verify that any support
1494 * functions needed for __int128 are present.
1496 * These are globals to discourage the compiler from folding all the
1497 * arithmetic tests down to compile-time constants. We do not have
1498 * convenient support for 128bit literals at this point...
1500 __int128 a = 48828125;
1501 __int128 b = 97656250;
1506 a = (a << 12) + 1; /* 200000000001 */
1507 b = (b << 12) + 5; /* 400000000005 */
1508 /* try the most relevant arithmetic ops */
1511 /* must use the results, else compiler may optimize arithmetic away */
1517 buggy_int128 = false
1519 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1520 # If not cross-compiling, we can test for bugs and disable use of __int128
1521 # with buggy compilers. If cross-compiling, hope for the best.
1522 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1523 if not meson.is_cross_build()
1525 /* This must match the corresponding code in c.h: */
1526 #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1527 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1528 #elif defined(_MSC_VER)
1529 #define pg_attribute_aligned(a) __declspec(align(a))
1531 typedef __int128 int128a
1532 #if defined(pg_attribute_aligned)
1533 pg_attribute_aligned(8)
1538 void pass_by_val(void *buffer, int128a par) { holder = par; }
1542 long int i64 = 97656225L << 12;
1544 pass_by_val(main, (int128a) i64);
1548 name: '__int128 alignment bug',
1550 assert(r.compiled())
1551 if r.returncode() != 0
1553 message('__int128 support present but buggy and thus disabled')
1558 cdata.set('PG_INT128_TYPE', '__int128')
1559 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
1560 alignment('__int128', args: test_c_args))
1565 # Check if the C compiler knows computed gotos (gcc extension, also
1566 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1568 # Checking whether computed gotos are supported syntax-wise ought to
1569 # be enough, as the syntax is otherwise illegal.
1571 static inline int foo(void)
1573 void *labeladdrs[] = {&&my_label};
1574 goto *labeladdrs[0];
1579 cdata.set('HAVE_COMPUTED_GOTO', 1)
1583 # Check if the C compiler understands _Static_assert(),
1584 # and define HAVE__STATIC_ASSERT if so.
1586 # We actually check the syntax ({ _Static_assert(...) }), because we need
1587 # gcc-style compound expressions to be able to wrap the thing into macros.
1589 int main(int arg, char **argv)
1591 ({ _Static_assert(1, "foo"); });
1595 cdata.set('HAVE__STATIC_ASSERT', 1)
1599 # We use <stdbool.h> if we have it and it declares type bool as having
1600 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1601 if cc.has_type('_Bool', args: test_c_args) \
1602 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1603 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1604 cdata.set('HAVE__BOOL', 1)
1605 cdata.set('PG_USE_STDBOOL', 1)
1609 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1610 # warning for each use of %m.
1611 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1613 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1614 static void call_log(void)
1616 emit_log(0, "error: %s: %m", "foo");
1619 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1620 foreach a : printf_attributes
1621 if cc.compiles(testsrc.format(a),
1622 args: test_c_args + attrib_error_args, name: 'format ' + a)
1623 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1629 if cc.has_function_attribute('visibility:default') and \
1630 cc.has_function_attribute('visibility:hidden')
1631 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1633 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1634 # inlineshidden to C code as well... Any either way, we want to put these
1635 # flags into exported files (pgxs, .pc files).
1636 cflags_mod += '-fvisibility=hidden'
1637 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1638 ldflags_mod += '-fvisibility=hidden'
1642 # Check if various builtins exist. Some builtins are tested separately,
1643 # because we want to test something more complicated than the generic case.
1656 foreach builtin : builtins
1657 fname = '__builtin_@0@'.format(builtin)
1658 if cc.has_function(fname, args: test_c_args)
1659 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1664 # Check if the C compiler understands __builtin_types_compatible_p,
1665 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1667 # We check usage with __typeof__, though it's unlikely any compiler would
1668 # have the former and not the latter.
1671 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1673 name: '__builtin_types_compatible_p',
1675 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1679 # Check if the C compiler understands __builtin_$op_overflow(),
1680 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1682 # Check for the most complicated case, 64 bit multiplication, as a
1683 # proxy for all of the operations. To detect the case where the compiler
1684 # knows the function but library support is missing, we must link not just
1685 # compile, and store the results in global variables so the compiler doesn't
1686 # optimize away the call.
1694 return __builtin_mul_overflow(a, b, &result);
1696 name: '__builtin_mul_overflow',
1697 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1699 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1703 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1704 # here. To prevent problems due to two detection methods working, stop
1705 # checking after one.
1708 int main(int arg, char **argv)
1710 unsigned int exx[4] = {0, 0, 0, 0};
1711 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1713 ''', name: '__get_cpuid',
1715 cdata.set('HAVE__GET_CPUID', 1)
1718 int main(int arg, char **argv)
1720 unsigned int exx[4] = {0, 0, 0, 0};
1723 ''', name: '__cpuid',
1725 cdata.set('HAVE__CPUID', 1)
1729 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1730 # versions of clang do not understand -fexcess-precision=standard, the use of
1731 # x87 floating point operations leads to problems like isinf possibly returning
1732 # false for a value that is infinite when converted from the 80bit register to
1733 # the 8byte memory representation.
1735 # Only perform the test if the compiler doesn't understand
1736 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1738 if '-fexcess-precision=standard' not in cflags
1739 if not cc.compiles('''
1740 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1743 name: '', args: test_c_args)
1744 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1750 ###############################################################
1752 ###############################################################
1754 common_functional_flags = [
1755 # Disable strict-aliasing rules; needed for gcc 3.3+
1756 '-fno-strict-aliasing',
1757 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1759 '-fexcess-precision=standard',
1762 cflags += cc.get_supported_arguments(common_functional_flags)
1764 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1767 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1768 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1770 common_warning_flags = [
1771 '-Wmissing-prototypes',
1773 # Really don't want VLAs to be used in our dialect of C
1775 # On macOS, complain about usage of symbols newer than the deployment target
1776 '-Werror=unguarded-availability-new',
1778 '-Wmissing-format-attribute',
1779 '-Wimplicit-fallthrough=3',
1780 '-Wcast-function-type',
1781 '-Wshadow=compatible-local',
1782 # This was included in -Wall/-Wformat in older GCC versions
1783 '-Wformat-security',
1786 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1788 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1791 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1792 # the result for them
1793 cflags_no_decl_after_statement = []
1794 if cc.has_argument('-Wdeclaration-after-statement')
1795 cflags_warn += '-Wdeclaration-after-statement'
1796 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1800 # The following tests want to suppress various unhelpful warnings by adding
1801 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1802 # switches, so we have to test for the positive form and if that works,
1803 # add the negative form.
1805 negative_warning_flags = [
1806 # Suppress clang's unhelpful unused-command-line-argument warnings.
1807 'unused-command-line-argument',
1809 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1810 # of warnings when building plperl because of usages in the Perl headers.
1811 'compound-token-split-by-macro',
1813 # Similarly disable useless truncation warnings from gcc 8+
1814 'format-truncation',
1815 'stringop-truncation',
1817 # Suppress clang 16's strict warnings about function casts
1818 'cast-function-type-strict',
1820 # To make warning_level=2 / -Wextra work, we'd need at least the following
1822 # 'missing-field-initializers',
1824 # 'unused-parameter',
1827 foreach w : negative_warning_flags
1828 if cc.has_argument('-W' + w)
1829 cflags_warn += '-Wno-' + w
1831 if llvm.found() and cpp.has_argument('-W' + w)
1832 cxxflags_warn += '-Wno-' + w
1838 if cc.get_id() == 'msvc'
1840 '/wd4018', # signed/unsigned mismatch
1841 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1842 '/wd4273', # inconsistent DLL linkage
1843 '/wd4101', # unreferenced local variable
1844 '/wd4102', # unreferenced label
1845 '/wd4090', # different 'modifier' qualifiers
1846 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1854 '/D_CRT_SECURE_NO_DEPRECATE',
1855 '/D_CRT_NONSTDC_NO_DEPRECATE',
1858 # We never need export libraries. As link.exe reports their creation, they
1859 # are unnecessarily noisy. Similarly, we don't need import library for
1860 # modules, we only import them dynamically, and they're also noisy.
1862 ldflags_mod += '/NOIMPLIB'
1867 ###############################################################
1869 ###############################################################
1871 if not get_option('spinlocks')
1872 warning('Not using spinlocks will cause poor performance')
1874 cdata.set('HAVE_SPINLOCKS', 1)
1877 if not get_option('atomics')
1878 warning('Not using atomics will cause poor performance')
1880 # XXX: perhaps we should require some atomics support in this case these
1882 cdata.set('HAVE_ATOMICS', 1)
1885 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1886 'desc': '__sync_lock_test_and_set(char)',
1889 __sync_lock_test_and_set(&lock, 1);
1890 __sync_lock_release(&lock);'''},
1892 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1893 'desc': '__sync_lock_test_and_set(int32)',
1896 __sync_lock_test_and_set(&lock, 1);
1897 __sync_lock_release(&lock);'''},
1899 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1900 'desc': '__sync_val_compare_and_swap(int32)',
1903 __sync_val_compare_and_swap(&val, 0, 37);'''},
1905 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1906 'desc': '__sync_val_compare_and_swap(int64)',
1909 __sync_val_compare_and_swap(&val, 0, 37);'''},
1911 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1912 'desc': ' __atomic_compare_exchange_n(int32)',
1916 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1918 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1919 'desc': ' __atomic_compare_exchange_n(int64)',
1923 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1926 foreach check : atomic_checks
1931 }'''.format(check['test'])
1933 cdata.set(check['name'],
1935 name: check['desc'],
1936 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
1944 ###############################################################
1945 # Select CRC-32C implementation.
1947 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
1948 # use the special CRC instructions for calculating CRC-32C. If we're not
1949 # targeting such a processor, but we can nevertheless produce code that uses
1950 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
1951 # implementations and select which one to use at runtime, depending on whether
1952 # SSE 4.2 is supported by the processor we're running on.
1954 # Similarly, if we are targeting an ARM processor that has the CRC
1955 # instructions that are part of the ARMv8 CRC Extension, use them. And if
1956 # we're not targeting such a processor, but can nevertheless produce code that
1957 # uses the CRC instructions, compile both, and select at runtime.
1958 ###############################################################
1960 have_optimized_crc = false
1962 if host_cpu == 'x86' or host_cpu == 'x86_64'
1964 if cc.get_id() == 'msvc'
1965 cdata.set('USE_SSE42_CRC32C', false)
1966 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1967 have_optimized_crc = true
1971 #include <nmmintrin.h>
1975 unsigned int crc = 0;
1976 crc = _mm_crc32_u8(crc, 0);
1977 crc = _mm_crc32_u32(crc, 0);
1978 /* return computed value, to prevent the above being optimized away */
1983 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
1985 # Use Intel SSE 4.2 unconditionally.
1986 cdata.set('USE_SSE42_CRC32C', 1)
1987 have_optimized_crc = true
1988 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
1989 args: test_c_args + ['-msse4.2'])
1990 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
1991 # the runtime check.
1992 cflags_crc += '-msse4.2'
1993 cdata.set('USE_SSE42_CRC32C', false)
1994 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
1995 have_optimized_crc = true
2000 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2003 #include <arm_acle.h>
2007 unsigned int crc = 0;
2008 crc = __crc32cb(crc, 0);
2009 crc = __crc32ch(crc, 0);
2010 crc = __crc32cw(crc, 0);
2011 crc = __crc32cd(crc, 0);
2013 /* return computed value, to prevent the above being optimized away */
2018 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2020 # Use ARM CRC Extension unconditionally
2021 cdata.set('USE_ARMV8_CRC32C', 1)
2022 have_optimized_crc = true
2023 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2024 args: test_c_args + ['-march=armv8-a+crc'])
2025 # Use ARM CRC Extension, with runtime check
2026 cflags_crc += '-march=armv8-a+crc'
2027 cdata.set('USE_ARMV8_CRC32C', false)
2028 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2029 have_optimized_crc = true
2033 if not have_optimized_crc
2034 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2036 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2041 ###############################################################
2042 # Other CPU specific stuff
2043 ###############################################################
2045 if host_cpu == 'x86_64'
2050 long long x = 1; long long r;
2051 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2053 name: '@0@: popcntq instruction'.format(host_cpu),
2055 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2058 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2059 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2060 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2063 addi(int ra, int si)
2066 if (__builtin_constant_p(si))
2067 __asm__ __volatile__(
2068 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2071 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2074 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2081 ###############################################################
2082 # Library / OS tests
2083 ###############################################################
2085 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2086 # unnecessary checks over and over, particularly on windows.
2100 'sys/personality.h',
2109 foreach header : header_checks
2110 varname = 'HAVE_' + header.underscorify().to_upper()
2112 # Emulate autoconf behaviour of not-found->undef, found->1
2113 found = cc.has_header(header,
2114 include_directories: postgres_inc, args: test_c_args)
2115 cdata.set(varname, found ? 1 : false,
2116 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2121 ['F_FULLFSYNC', 'fcntl.h'],
2122 ['fdatasync', 'unistd.h'],
2123 ['posix_fadvise', 'fcntl.h'],
2124 ['strlcat', 'string.h'],
2125 ['strlcpy', 'string.h'],
2126 ['strnlen', 'string.h'],
2129 # Need to check for function declarations for these functions, because
2130 # checking for library symbols wouldn't handle deployment target
2131 # restrictions on macOS
2133 ['preadv', 'sys/uio.h'],
2134 ['pwritev', 'sys/uio.h'],
2137 foreach c : decl_checks
2141 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2143 found = cc.has_header_symbol(header, func,
2144 args: test_c_args, include_directories: postgres_inc,
2146 cdata.set10(varname, found, description:
2147 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2148 don't.'''.format(func))
2152 if cc.has_type('struct option',
2153 args: test_c_args, include_directories: postgres_inc,
2154 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2155 cdata.set('HAVE_STRUCT_OPTION', 1)
2159 foreach c : ['opterr', 'optreset']
2160 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2169 '''.format(c), name: c, args: test_c_args)
2170 cdata.set(varname, 1)
2172 cdata.set(varname, false)
2176 if cc.has_type('socklen_t',
2177 args: test_c_args, include_directories: postgres_inc,
2179 #include <sys/socket.h>''')
2180 cdata.set('HAVE_SOCKLEN_T', 1)
2183 if cc.has_member('struct sockaddr', 'sa_len',
2184 args: test_c_args, include_directories: postgres_inc,
2186 #include <sys/types.h>
2187 #include <sys/socket.h>''')
2188 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2191 if cc.has_member('struct tm', 'tm_zone',
2192 args: test_c_args, include_directories: postgres_inc,
2194 #include <sys/types.h>
2197 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2202 extern int foo(void);
2205 return timezone / 60;
2208 name: 'global variable `timezone\' exists',
2209 args: test_c_args, include_directories: postgres_inc)
2210 cdata.set('HAVE_INT_TIMEZONE', 1)
2212 cdata.set('HAVE_INT_TIMEZONE', false)
2215 if cc.has_type('union semun',
2217 include_directories: postgres_inc,
2219 #include <sys/types.h>
2220 #include <sys/ipc.h>
2221 #include <sys/sem.h>
2223 cdata.set('HAVE_UNION_SEMUN', 1)
2231 switch (strerror_r(1, buf, sizeof(buf)))
2232 { case 0: break; default: break; }
2235 args: test_c_args, include_directories: postgres_inc)
2236 cdata.set('STRERROR_R_INT', 1)
2238 cdata.set('STRERROR_R_INT', false)
2241 # Check for the locale_t type and find the right header file. macOS
2242 # needs xlocale.h; standard is locale.h, but glibc also has an
2243 # xlocale.h file that we should not use. MSVC has a replacement
2244 # defined in src/include/port/win32_port.h.
2245 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2246 cdata.set('HAVE_LOCALE_T', 1)
2247 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2248 cdata.set('HAVE_LOCALE_T', 1)
2249 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2250 elif cc.get_id() == 'msvc'
2251 cdata.set('HAVE_LOCALE_T', 1)
2254 # Check if the C compiler understands typeof or a variant. Define
2255 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2256 foreach kw : ['typeof', '__typeof__', 'decltype']
2267 args: test_c_args, include_directories: postgres_inc)
2269 cdata.set('HAVE_TYPEOF', 1)
2271 cdata.set('typeof', kw)
2279 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2280 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2281 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2282 wcstombs_l_test = '''
2294 if (not cc.compiles(wcstombs_l_test.format(''),
2295 name: 'wcstombs_l') and
2296 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2297 name: 'wcstombs_l in xlocale.h'))
2298 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2302 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2303 # understands, because it conflicts with __declspec(restrict). Therefore we
2304 # define pg_restrict to the appropriate definition, which presumably won't
2307 # We assume C99 support, so we don't need to make this conditional.
2309 # XXX: Historically we allowed platforms to disable restrict in template
2310 # files, but that was only added for AIX when building with XLC, which we
2311 # don't support yet.
2312 cdata.set('pg_restrict', '__restrict')
2315 # Most libraries are included only if they demonstrably provide a function we
2316 # need, but libm is an exception: always include it, because there are too
2317 # many compilers that play cute optimization games that will break probes for
2318 # standard functions such as pow().
2319 os_deps += cc.find_library('m', required: false)
2321 rt_dep = cc.find_library('rt', required: false)
2323 dl_dep = cc.find_library('dl', required: false)
2325 util_dep = cc.find_library('util', required: false)
2326 posix4_dep = cc.find_library('posix4', required: false)
2328 getopt_dep = cc.find_library('getopt', required: false)
2329 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2330 # Check if we want to replace getopt/getopt_long even if provided by the system
2331 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2332 # so always use our version on Windows
2333 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2334 # (i.e., allow '-' as a flag character), so use our version on those platforms
2335 # - We want to use system's getopt_long() only if the system provides struct
2337 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2338 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2341 execinfo_dep = cc.find_library('execinfo', required: false)
2343 if host_system == 'cygwin'
2344 cygipc_dep = cc.find_library('cygipc', required: false)
2346 cygipc_dep = not_found_dep
2349 if host_system == 'sunos'
2350 socket_dep = cc.find_library('socket', required: false)
2352 socket_dep = not_found_dep
2355 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2356 # unnecessary checks over and over, particularly on windows.
2358 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2359 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2360 ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2362 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2363 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2364 # required. Just checking for dlsym() ought to suffice.
2365 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2367 ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2369 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2370 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2380 ['posix_fallocate'],
2383 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2384 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2385 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2386 ['setproctitle', {'dependencies': [util_dep]}],
2387 ['setproctitle_fast'],
2388 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2389 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2390 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2391 ['socket', {'dependencies': [socket_dep], 'define': false}],
2393 ['strerror_r', {'dependencies': [thread_dep]}],
2398 ['sync_file_range'],
2404 func_check_results = {}
2405 foreach c : func_checks
2407 kwargs = c.get(1, {})
2408 deps = kwargs.get('dependencies', [])
2410 if kwargs.get('skip', false)
2414 found = cc.has_function(func, args: test_c_args)
2421 found = cc.has_function(func, args: test_c_args,
2422 dependencies: [dep])
2430 func_check_results += {func: found}
2432 if kwargs.get('define', true)
2433 # Emulate autoconf behaviour of not-found->undef, found->1
2434 cdata.set('HAVE_' + func.underscorify().to_upper(),
2436 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2441 if cc.has_function('syslog', args: test_c_args) and \
2442 cc.check_header('syslog.h', args: test_c_args)
2443 cdata.set('HAVE_SYSLOG', 1)
2447 # MSVC has replacements defined in src/include/port/win32_port.h.
2448 if cc.get_id() == 'msvc'
2449 cdata.set('HAVE_WCSTOMBS_L', 1)
2450 cdata.set('HAVE_MBSTOWCS_L', 1)
2454 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2456 if sema_kind == 'unnamed_posix' and \
2457 not func_check_results.get('sem_init', false)
2461 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2462 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2464 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2465 cdata.set_quoted('DLSUFFIX', dlsuffix)
2468 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2469 cdata.set_quoted('PG_VERSION_STR',
2470 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2471 pg_version, host_machine.cpu_family(), host_system,
2472 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2478 ###############################################################
2480 ###############################################################
2482 # XXX: About to rely on thread safety in the autoconf build, so not worth
2483 # implementing a fallback.
2484 cdata.set('ENABLE_THREAD_SAFETY', 1)
2488 ###############################################################
2490 ###############################################################
2492 nlsopt = get_option('nls')
2493 libintl = not_found_dep
2495 if not nlsopt.disabled()
2496 # otherwise there'd be lots of
2497 # "Gettext not found, all translation (po) targets will be ignored."
2498 # warnings if not found.
2499 msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
2501 # meson 0.59 has this wrapped in dependency('int')
2502 if (msgfmt.found() and
2503 cc.check_header('libintl.h', required: nlsopt,
2504 args: test_c_args, include_directories: postgres_inc))
2507 if cc.has_function('ngettext')
2508 libintl = declare_dependency()
2510 libintl = cc.find_library('intl',
2511 has_headers: ['libintl.h'], required: nlsopt,
2512 header_include_directories: postgres_inc,
2518 i18n = import('i18n')
2519 cdata.set('ENABLE_NLS', 1)
2525 ###############################################################
2527 ###############################################################
2529 # Set up compiler / linker arguments to be used everywhere, individual targets
2530 # can add further args directly, or indirectly via dependencies
2531 add_project_arguments(cflags, language: ['c'])
2532 add_project_arguments(cppflags, language: ['c'])
2533 add_project_arguments(cflags_warn, language: ['c'])
2534 add_project_arguments(cxxflags, language: ['cpp'])
2535 add_project_arguments(cppflags, language: ['cpp'])
2536 add_project_arguments(cxxflags_warn, language: ['cpp'])
2537 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2540 # Collect a number of lists of things while recursing through the source
2541 # tree. Later steps then can use those.
2543 # list of targets for various alias targets
2544 backend_targets = []
2547 contrib_targets = []
2548 testprep_targets = []
2552 # Define the tests to distribute them to the correct test styles later
2557 # Default options for targets
2559 # First identify rpaths
2560 bin_install_rpaths = []
2561 lib_install_rpaths = []
2562 mod_install_rpaths = []
2565 # Don't add rpaths on darwin for now - as long as only absolute references to
2566 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2567 # their final destination.
2568 if host_system != 'darwin'
2569 # Add absolute path to libdir to rpath. This ensures installed binaries /
2570 # libraries find our libraries (mainly libpq).
2571 bin_install_rpaths += dir_prefix / dir_lib
2572 lib_install_rpaths += dir_prefix / dir_lib
2573 mod_install_rpaths += dir_prefix / dir_lib
2575 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2577 # Not needed on darwin even if we use relative rpaths for our own libraries,
2578 # as the install_name of libraries in extra_lib_dirs will point to their
2580 bin_install_rpaths += postgres_lib_d
2581 lib_install_rpaths += postgres_lib_d
2582 mod_install_rpaths += postgres_lib_d
2586 # Define arguments for default targets
2588 default_target_args = {
2589 'implicit_include_directories': false,
2593 default_lib_args = default_target_args + {
2597 internal_lib_args = default_lib_args + {
2598 'build_by_default': false,
2602 default_mod_args = default_lib_args + {
2604 'install_dir': dir_lib_pkg,
2607 default_bin_args = default_target_args + {
2608 'install_dir': dir_bin,
2611 if get_option('rpath')
2612 default_lib_args += {
2613 'install_rpath': ':'.join(lib_install_rpaths),
2616 default_mod_args += {
2617 'install_rpath': ':'.join(mod_install_rpaths),
2620 default_bin_args += {
2621 'install_rpath': ':'.join(bin_install_rpaths),
2626 # Helper for exporting a limited number of symbols
2627 gen_export_kwargs = {
2628 'input': 'exports.txt',
2629 'output': '@BASENAME@.'+export_file_suffix,
2630 'command': [perl, files('src/tools/gen_export.pl'),
2631 '--format', export_file_format,
2632 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2633 'build_by_default': false,
2640 ### windows resources related stuff
2643 if host_system == 'windows'
2644 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2645 win32ver_rc = files('src/port/win32ver.rc')
2646 rcgen = find_program('src/tools/rcgen', native: true)
2649 '--srcdir', '@SOURCE_DIR@',
2650 '--builddir', meson.build_root(),
2651 '--rcout', '@OUTPUT0@',
2652 '--out', '@OUTPUT1@',
2653 '--input', '@INPUT@',
2657 if cc.get_argument_syntax() == 'msvc'
2658 rc = find_program('rc', required: true)
2659 rcgen_base_args += ['--rc', rc.path()]
2660 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2662 windres = find_program('windres', required: true)
2663 rcgen_base_args += ['--windres', windres.path()]
2664 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2667 # msbuild backend doesn't support this atm
2668 if meson.backend() == 'ninja'
2669 rcgen_base_args += ['--depfile', '@DEPFILE@']
2672 rcgen_bin_args = rcgen_base_args + [
2673 '--VFT_TYPE', 'VFT_APP',
2674 '--FILEENDING', 'exe',
2678 rcgen_lib_args = rcgen_base_args + [
2679 '--VFT_TYPE', 'VFT_DLL',
2680 '--FILEENDING', 'dll',
2683 rc_bin_gen = generator(rcgen,
2684 depfile: '@BASENAME@.d',
2685 arguments: rcgen_bin_args,
2686 output: rcgen_outputs,
2689 rc_lib_gen = generator(rcgen,
2690 depfile: '@BASENAME@.d',
2691 arguments: rcgen_lib_args,
2692 output: rcgen_outputs,
2698 # headers that the whole build tree depends on
2699 generated_headers = []
2700 # headers that the backend build depends on
2701 generated_backend_headers = []
2702 # configure_files() output, needs a way of converting to file names
2703 configure_files = []
2705 # generated files that might conflict with a partial in-tree autoconf build
2706 generated_sources = []
2707 # same, for paths that differ between autoconf / meson builds
2708 # elements are [dir, [files]]
2709 generated_sources_ac = {}
2712 # First visit src/include - all targets creating headers are defined
2713 # within. That makes it easy to add the necessary dependencies for the
2714 # subsequent build steps.
2716 subdir('src/include')
2720 # Then through src/port and src/common, as most other things depend on them
2722 frontend_port_code = declare_dependency(
2723 compile_args: ['-DFRONTEND'],
2724 include_directories: [postgres_inc],
2725 dependencies: os_deps,
2728 backend_port_code = declare_dependency(
2729 compile_args: ['-DBUILDING_DLL'],
2730 include_directories: [postgres_inc],
2731 sources: [errcodes], # errcodes.h is needed due to use of ereport
2732 dependencies: os_deps,
2737 frontend_common_code = declare_dependency(
2738 compile_args: ['-DFRONTEND'],
2739 include_directories: [postgres_inc],
2740 sources: generated_headers,
2741 dependencies: [os_deps, zlib, zstd],
2744 backend_common_code = declare_dependency(
2745 compile_args: ['-DBUILDING_DLL'],
2746 include_directories: [postgres_inc],
2747 sources: generated_headers,
2748 dependencies: [os_deps, zlib, zstd],
2751 subdir('src/common')
2753 # all shared libraries should depend on shlib_code
2754 shlib_code = declare_dependency(
2755 link_args: ldflags_sl,
2758 # all static libraries not part of the backend should depend on this
2759 frontend_stlib_code = declare_dependency(
2760 include_directories: [postgres_inc],
2761 link_with: [common_static, pgport_static],
2762 sources: generated_headers,
2763 dependencies: [os_deps, libintl],
2766 # all shared libraries not part of the backend should depend on this
2767 frontend_shlib_code = declare_dependency(
2768 include_directories: [postgres_inc],
2769 link_with: [common_shlib, pgport_shlib],
2770 sources: generated_headers,
2771 dependencies: [shlib_code, os_deps, libintl],
2774 # Dependencies both for static and shared libpq
2784 subdir('src/interfaces/libpq')
2785 # fe_utils depends on libpq
2786 subdir('src/fe_utils')
2788 # for frontend binaries
2789 frontend_code = declare_dependency(
2790 include_directories: [postgres_inc],
2791 link_with: [fe_utils, common_static, pgport_static],
2792 sources: generated_headers,
2793 dependencies: [os_deps, libintl],
2796 backend_both_deps += [
2813 backend_mod_deps = backend_both_deps + os_deps
2815 backend_code = declare_dependency(
2816 compile_args: ['-DBUILDING_DLL'],
2817 include_directories: [postgres_inc],
2818 link_args: ldflags_be,
2820 sources: generated_headers + generated_backend_headers,
2821 dependencies: os_deps + backend_both_deps + backend_deps,
2824 # install these files only during test, not main install
2825 test_install_data = []
2826 test_install_libs = []
2828 # src/backend/meson.build defines backend_mod_code used for extension
2832 # Then through the main sources. That way contrib can have dependencies on
2833 # main sources. Note that this explicitly doesn't enter src/test, right now a
2834 # few regression tests depend on contrib files.
2841 subdir('src/interfaces/libpq/test')
2842 subdir('src/interfaces/ecpg/test')
2844 subdir('doc/src/sgml')
2846 generated_sources_ac += {'': ['GNUmakefile']}
2848 # After processing src/test, add test_install_libs to the testprep_targets
2850 testprep_targets += test_install_libs
2853 # If there are any files in the source directory that we also generate in the
2854 # build directory, they might get preferred over the newly generated files,
2855 # e.g. because of a #include "file", which always will search in the current
2857 message('checking for file conflicts between source and build directory')
2858 conflicting_files = []
2859 potentially_conflicting_files_t = []
2860 potentially_conflicting_files_t += generated_headers
2861 potentially_conflicting_files_t += generated_backend_headers
2862 potentially_conflicting_files_t += generated_backend_sources
2863 potentially_conflicting_files_t += generated_sources
2865 potentially_conflicting_files = []
2867 # convert all sources of potentially conflicting files into uniform shape
2868 foreach t : potentially_conflicting_files_t
2869 potentially_conflicting_files += t.full_path()
2871 foreach t : configure_files
2873 potentially_conflicting_files += meson.current_build_dir() / t
2875 foreach sub, fnames : generated_sources_ac
2876 sub = meson.build_root() / sub
2877 foreach fname : fnames
2878 potentially_conflicting_files += sub / fname
2882 # find and report conflicting files
2883 foreach build_path : potentially_conflicting_files
2884 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
2885 # str.replace is in 0.56
2886 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
2887 if fs.exists(src_path) or fs.is_symlink(src_path)
2888 conflicting_files += src_path
2891 # XXX: Perhaps we should generate a file that would clean these up? The list
2893 if conflicting_files.length() > 0
2894 errmsg_cleanup = '''
2895 Conflicting files in source directory:
2898 The conflicting files need to be removed, either by removing the files listed
2899 above, or by running configure and then make maintainer-clean.
2901 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
2902 error(errmsg_nonclean_base.format(errmsg_cleanup))
2907 ###############################################################
2909 ###############################################################
2912 # We want to define additional install targets beyond what meson provides. For
2913 # that we need to define targets depending on nearly everything. We collected
2914 # the results of i18n.gettext() invocations into nls_targets, that also
2915 # includes maintainer targets though. Collect the ones we want as a dependency.
2917 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
2918 # generation happens during install, so that's not a real issue.
2920 if libintl.found() and meson.version().version_compare('>=0.60')
2921 # use range() to avoid the flattening of the list that forech() would do
2922 foreach off : range(0, nls_targets.length())
2923 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
2924 # -pot target 3) maintainer -pot target
2925 nls_mo_targets += nls_targets[off][0]
2927 alias_target('nls', nls_mo_targets)
2942 # Meson's default install target is quite verbose. Provide one that is quiet.
2943 install_quiet = custom_target('install-quiet',
2944 output: 'install-quiet',
2945 build_always_stale: true,
2946 build_by_default: false,
2947 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
2951 # Target to install files used for tests, which aren't installed by default
2952 install_test_files_args = [
2954 '--prefix', dir_prefix,
2955 '--install', contrib_data_dir, test_install_data,
2956 '--install', dir_lib_pkg, test_install_libs,
2958 run_target('install-test-files',
2959 command: [python] + install_test_files_args,
2960 depends: testprep_targets,
2965 ###############################################################
2967 ###############################################################
2969 # DESTDIR for the installation we'll run tests in
2970 test_install_destdir = meson.build_root() / 'tmp_install/'
2972 # DESTDIR + prefix appropriately munged
2973 if build_system != 'windows'
2974 # On unixoid systems this is trivial, we just prepend the destdir
2975 assert(dir_prefix.startswith('/')) # enforced by meson
2976 test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
2978 # drives, drive-relative paths, etc make this complicated on windows, call
2979 # into a copy of meson's logic for it
2982 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
2983 test_install_destdir, dir_prefix]
2984 test_install_location = run_command(command, check: true).stdout().strip()
2987 meson_install_args = meson_args + ['install'] + {
2988 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
2992 # setup tests should be run first,
2993 # so define priority for these
2994 setup_tests_priority = 100
2996 meson_bin, args: meson_install_args ,
2997 env: {'DESTDIR':test_install_destdir},
2998 priority: setup_tests_priority,
3003 test('install_test_files',
3005 args: install_test_files_args + ['--destdir', test_install_destdir],
3006 priority: setup_tests_priority,
3010 test_result_dir = meson.build_root() / 'testrun'
3013 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3014 # inevitable conflicts from running tests in parallel, hackishly assign
3015 # different ports for different tests.
3019 test_env = environment()
3021 temp_install_bindir = test_install_location / get_option('bindir')
3022 test_env.set('PG_REGRESS', pg_regress.full_path())
3023 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3025 # Test suites that are not safe by default but can be run if selected
3026 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3027 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3028 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3030 # Add the temporary installation to the library search path on platforms where
3031 # that works (everything but windows, basically). On windows everything
3032 # library-like gets installed into bindir, solving that issue.
3033 if library_path_var != ''
3034 test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3039 ###############################################################
3041 ###############################################################
3043 # When using a meson version understanding exclude_suites, define a
3044 # 'tmp_install' test setup (the default) that excludes tests running against a
3045 # pre-existing install and a 'running' setup that conflicts with creation of
3046 # the temporary installation and tap tests (which don't support running
3047 # against a running server).
3051 if meson.version().version_compare('>=0.57')
3054 runningcheck = false
3057 testwrap = files('src/tools/testwrap')
3059 foreach test_dir : tests
3062 '--basedir', meson.build_root(),
3063 '--srcdir', test_dir['sd'],
3066 foreach kind, v : test_dir
3067 if kind in ['sd', 'bd', 'name']
3073 if kind in ['regress', 'isolation', 'ecpg']
3074 if kind == 'regress'
3076 fallback_dbname = 'regression_@0@'
3077 elif kind == 'isolation'
3078 runner = pg_isolation_regress
3079 fallback_dbname = 'isolation_regression_@0@'
3081 runner = pg_regress_ecpg
3082 fallback_dbname = 'ecpg_regression_@0@'
3085 test_group = test_dir['name']
3086 test_group_running = test_dir['name'] + '-running'
3088 test_output = test_result_dir / test_group / kind
3089 test_output_running = test_result_dir / test_group_running/ kind
3091 # Unless specified by the test, choose a non-conflicting database name,
3092 # to avoid conflicts when running against existing server.
3093 dbname = t.get('dbname',
3094 fallback_dbname.format(test_dir['name']))
3096 test_command_base = [
3098 '--inputdir', t.get('inputdir', test_dir['sd']),
3099 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3101 '--dlpath', test_dir['bd'],
3102 '--max-concurrent-tests=20',
3104 ] + t.get('regress_args', [])
3107 if t.has_key('schedule')
3108 test_selection += ['--schedule', t['schedule'],]
3111 if kind == 'isolation'
3112 test_selection += t.get('specs', [])
3114 test_selection += t.get('sql', [])
3118 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3123 'depends': test_deps + t.get('deps', []),
3125 } + t.get('test_kwargs', {})
3127 test(test_group / kind,
3131 '--testgroup', test_group,
3135 '--outputdir', test_output,
3136 '--temp-instance', test_output / 'tmp_check',
3137 '--port', testport.to_string(),
3141 kwargs: test_kwargs,
3143 install_suites += test_group
3145 # some tests can't support running against running DB
3146 if runningcheck and t.get('runningcheck', true)
3147 test(test_group_running / kind,
3151 '--testgroup', test_group_running,
3155 '--outputdir', test_output_running,
3158 is_parallel: t.get('runningcheck-parallel', true),
3159 suite: test_group_running,
3160 kwargs: test_kwargs,
3162 running_suites += test_group_running
3167 if not tap_tests_enabled
3173 '-I', meson.source_root() / 'src/test/perl',
3174 '-I', test_dir['sd'],
3177 # Add temporary install, the build directory for non-installed binaries and
3178 # also test/ for non-installed test binaries built separately.
3180 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3182 foreach name, value : t.get('env', {})
3183 env.set(name, value)
3186 test_group = test_dir['name']
3189 'suite': test_group,
3191 'depends': test_deps + t.get('deps', []),
3193 } + t.get('test_kwargs', {})
3195 foreach onetap : t['tests']
3196 # Make tap test names prettier, remove t/ and .pl
3198 if onetap_p.startswith('t/')
3199 onetap_p = onetap.split('t/')[1]
3201 if onetap_p.endswith('.pl')
3202 onetap_p = fs.stem(onetap_p)
3205 test(test_dir['name'] / onetap_p,
3207 kwargs: test_kwargs,
3208 args: testwrap_base + [
3209 '--testgroup', test_dir['name'],
3210 '--testname', onetap_p,
3212 test_dir['sd'] / onetap,
3216 install_suites += test_group
3218 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3221 endforeach # kinds of tests
3223 endforeach # directories with tests
3225 # repeat condition so meson realizes version dependency
3226 if meson.version().version_compare('>=0.57')
3227 add_test_setup('tmp_install',
3229 exclude_suites: running_suites)
3230 add_test_setup('running',
3231 exclude_suites: ['setup'] + install_suites)
3236 ###############################################################
3238 ###############################################################
3240 alias_target('backend', backend_targets)
3241 alias_target('bin', bin_targets + [libpq_st])
3242 alias_target('pl', pl_targets)
3243 alias_target('contrib', contrib_targets)
3244 alias_target('testprep', testprep_targets)
3245 alias_target('install-world', install_quiet, installdocs)
3249 ###############################################################
3250 # The End, The End, My Friend
3251 ###############################################################
3253 if meson.version().version_compare('>=0.57')
3257 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3258 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3259 'segment size': get_option('segsize_blocks') != 0 ?
3260 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3261 '@0@ GB'.format(get_option('segsize')),
3263 section: 'Data layout',
3268 'host system': '@0@ @1@'.format(host_system, host_cpu),
3269 'build system': '@0@ @1@'.format(build_machine.system(),
3270 build_machine.cpu_family()),
3277 'linker': '@0@'.format(cc.get_linker_id()),
3278 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3280 section: 'Compiler',
3285 'CPP FLAGS': ' '.join(cppflags),
3286 'C FLAGS, functional': ' '.join(cflags),
3287 'C FLAGS, warnings': ' '.join(cflags_warn),
3288 'C FLAGS, modules': ' '.join(cflags_mod),
3289 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3290 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3292 section: 'Compiler Flags',
3298 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3300 section: 'Compiler',
3305 'C++ FLAGS, functional': ' '.join(cxxflags),
3306 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3307 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3309 section: 'Compiler Flags',
3315 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3318 section: 'Programs',
3324 'bsd_auth': bsd_auth,
3336 'plpython': python3_dep,
3338 'readline': readline,
3345 section: 'External libraries',