1 # Copyright (c) 2022-2025, 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 distclean in the source tree.'
76 error(errmsg_nonclean_base.format(errmsg_cleanup))
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
88 postgres_lib_d = get_option('extra_lib_dirs')
107 backend_both_deps = []
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
122 pg_version = meson.project_version()
124 if pg_version.endswith('devel')
125 pg_version_arr = [pg_version.split('devel')[0], '0']
126 elif pg_version.contains('beta')
127 pg_version_arr = [pg_version.split('beta')[0], '0']
128 elif pg_version.contains('rc')
129 pg_version_arr = [pg_version.split('rc')[0], '0']
131 pg_version_arr = pg_version.split('.')
134 pg_version_major = pg_version_arr[0].to_int()
135 pg_version_minor = pg_version_arr[1].to_int()
136 pg_version_num = (pg_version_major * 10000) + pg_version_minor
138 pg_url = 'https://www.postgresql.org/'
140 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
141 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
142 cdata.set_quoted('PACKAGE_URL', pg_url)
143 cdata.set_quoted('PACKAGE_VERSION', pg_version)
144 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
145 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
147 pg_version += get_option('extra_version')
148 cdata.set_quoted('PG_VERSION', pg_version)
149 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
150 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
151 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
152 cdata.set('PG_VERSION_NUM', pg_version_num)
153 # PG_VERSION_STR is built later, it depends on compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 exesuffix = '' # overridden below where necessary
163 dlsuffix = '.so' # overridden below where necessary
164 library_path_var = 'LD_LIBRARY_PATH'
166 # Format of file to control exports from libraries, and how to pass them to
167 # the compiler. For export_fmt @0@ is the path to the file export file.
168 export_file_format = 'gnu'
169 export_file_suffix = 'list'
170 export_fmt = '-Wl,--version-script=@0@'
172 # Flags to add when linking a postgres extension, @0@ is path to
173 # the relevant object on the platform.
174 mod_link_args_fmt = []
176 memset_loop_limit = 1024
178 # Choice of shared memory and semaphore implementation
182 # We implement support for some operating systems by pretending they're
183 # another. Map here, before determining system properties below
184 if host_system == 'dragonfly'
185 # apparently the most similar
186 host_system = 'netbsd'
187 elif host_system == 'android'
188 # while android isn't quite a normal linux, it seems close enough
189 # for our purposes so far
190 host_system = 'linux'
193 # meson's system names don't quite map to our "traditional" names. In some
194 # places we need the "traditional" name, e.g., for mapping
195 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
197 portname = host_system
199 if host_system == 'cygwin'
200 sema_kind = 'unnamed_posix'
201 cppflags += '-D_GNU_SOURCE'
203 mod_link_args_fmt = ['@0@']
204 mod_link_with_name = 'lib@0@.a'
205 mod_link_with_dir = 'libdir'
207 elif host_system == 'darwin'
209 library_path_var = 'DYLD_LIBRARY_PATH'
211 export_file_format = 'darwin'
212 export_fmt = '-Wl,-exported_symbols_list,@0@'
214 mod_link_args_fmt = ['-bundle_loader', '@0@']
215 mod_link_with_dir = 'bindir'
216 mod_link_with_name = '@0@'
218 sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
219 pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
220 message('darwin sysroot: @0@'.format(pg_sysroot))
222 cflags += ['-isysroot', pg_sysroot]
223 ldflags += ['-isysroot', pg_sysroot]
226 # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
227 # don't want because a) it's different from what we do for autoconf, b) it
228 # causes warnings in macOS Ventura. But using -Wl,-undefined,error causes a
229 # warning starting in Sonoma. So only add -Wl,-undefined,error if it does
230 # not cause a warning.
231 if cc.has_multi_link_arguments('-Wl,-undefined,error', '-Werror')
232 ldflags_mod += '-Wl,-undefined,error'
235 # Starting in Sonoma, the linker warns about the same library being
236 # linked twice. Which can easily happen when multiple dependencies
237 # depend on the same library. Quiesce the ill considered warning.
238 ldflags += cc.get_supported_link_arguments('-Wl,-no_warn_duplicate_libraries')
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 # We need these #defines to get POSIX-conforming versions
265 # of many interfaces (sigwait, getpwuid_r, shmdt, ...).
267 '-D_POSIX_C_SOURCE=200112L',
269 '-D_POSIX_PTHREAD_SEMANTICS',
272 elif host_system == 'windows'
276 library_path_var = ''
277 if cc.get_id() != 'msvc'
278 # define before including <time.h> for getting localtime_r() etc. on MinGW
279 cppflags += '-D_POSIX_C_SOURCE'
282 export_file_format = 'win'
283 export_file_suffix = 'def'
284 if cc.get_id() == 'msvc'
285 export_fmt = '/DEF:@0@'
286 mod_link_with_name = '@0@.lib'
289 mod_link_with_name = 'lib@0@.a'
291 mod_link_args_fmt = ['@0@']
292 mod_link_with_dir = 'libdir'
297 cdata.set('WIN32_STACK_RLIMIT', 4194304)
298 if cc.get_id() == 'msvc'
299 ldflags += '/INCREMENTAL:NO'
300 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
301 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
303 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
304 # Need to allow multiple definitions, we e.g. want to override getopt.
305 ldflags += '-Wl,--allow-multiple-definition'
306 # Ensure we get MSVC-like linking behavior.
307 ldflags += '-Wl,--disable-auto-import'
310 os_deps += cc.find_library('ws2_32', required: true)
311 secur32_dep = cc.find_library('secur32', required: true)
312 backend_deps += secur32_dep
313 libpq_deps += secur32_dep
315 postgres_inc_d += 'src/include/port/win32'
316 if cc.get_id() == 'msvc'
317 postgres_inc_d += 'src/include/port/win32_msvc'
320 windows = import('windows')
323 # XXX: Should we add an option to override the host_system as an escape
325 error('unknown host system: @0@'.format(host_system))
330 ###############################################################
332 ###############################################################
335 perl = find_program(get_option('PERL'), required: true, native: true)
336 python = find_program(get_option('PYTHON'), required: true, native: true)
337 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
338 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
339 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
340 prove = find_program(get_option('PROVE'), native: true, required: false)
341 tar = find_program(get_option('TAR'), native: true, required: false)
342 gzip = find_program(get_option('GZIP'), native: true, required: false)
343 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
344 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
345 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
346 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
347 missing = find_program('config/missing', native: true)
348 cp = find_program('cp', required: false, native: true)
349 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
350 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
354 bison_version_c = run_command(bison, '--version', check: true)
355 # bison version string helpfully is something like
356 # >>bison (GNU bison) 3.8.1<<
357 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
358 if bison_version.version_compare('>=3.0')
359 bison_flags += ['-Wno-deprecated']
362 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
364 'output': ['@BASENAME@.c', '@BASENAME@.h'],
365 'command': bison_cmd,
370 flex_version_c = run_command(flex, '--version', check: true)
371 flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
373 flex_wrapper = files('src/tools/pgflex')
374 flex_cmd = [python, flex_wrapper,
375 '--builddir', '@BUILD_ROOT@',
376 '--srcdir', '@SOURCE_ROOT@',
377 '--privatedir', '@PRIVATE_DIR@',
378 '--flex', flex, '--perl', perl,
379 '-i', '@INPUT@', '-o', '@OUTPUT0@',
382 wget = find_program('wget', required: false, native: true)
383 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
385 install_files = files('src/tools/install_files')
389 ###############################################################
390 # Path to meson (for tests etc)
391 ###############################################################
393 # NB: this should really be part of meson, see
394 # https://github.com/mesonbuild/meson/issues/8511
395 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
397 if meson_binpath_r.stdout() == ''
398 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
399 meson_binpath_r.returncode(),
400 meson_binpath_r.stdout(),
401 meson_binpath_r.stderr()))
404 meson_binpath_s = meson_binpath_r.stdout().split('\n')
405 meson_binpath_len = meson_binpath_s.length()
407 if meson_binpath_len < 1
408 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
415 foreach e : meson_binpath_s
426 if meson_impl not in ['muon', 'meson']
427 error('unknown meson implementation "@0@"'.format(meson_impl))
430 meson_bin = find_program(meson_binpath, native: true)
434 ###############################################################
436 ###############################################################
438 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
439 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
441 blocksize = get_option('blocksize').to_int() * 1024
443 if get_option('segsize_blocks') != 0
444 if get_option('segsize') != 1
445 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
448 segsize = get_option('segsize_blocks')
450 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
453 cdata.set('BLCKSZ', blocksize, description:
454 '''Size of a disk block --- this also limits the size of a tuple. You can set
455 it bigger if you need bigger tuples (although TOAST should reduce the need
456 to have large tuples, since fields can be spread across multiple tuples).
457 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
458 currently 2^15 (32768). This is determined by the 15-bit widths of the
459 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
460 Changing BLCKSZ requires an initdb.''')
462 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
463 cdata.set('RELSEG_SIZE', segsize)
464 cdata.set('DEF_PGPORT', get_option('pgport'))
465 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
466 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
467 if get_option('system_tzdata') != ''
468 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
473 ###############################################################
475 ###############################################################
477 # These are set by the equivalent --xxxdir configure options. We
478 # append "postgresql" to some of them, if the string does not already
479 # contain "pgsql" or "postgres", in order to avoid directory clutter.
483 dir_prefix = get_option('prefix')
485 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
487 dir_bin = get_option('bindir')
489 dir_data = get_option('datadir')
490 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
491 dir_data = dir_data / pkg
494 dir_sysconf = get_option('sysconfdir')
495 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
496 dir_sysconf = dir_sysconf / pkg
499 dir_lib = get_option('libdir')
501 dir_lib_pkg = dir_lib
502 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
503 dir_lib_pkg = dir_lib_pkg / pkg
506 dir_pgxs = dir_lib_pkg / 'pgxs'
508 dir_include = get_option('includedir')
510 dir_include_pkg = dir_include
511 dir_include_pkg_rel = ''
512 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
513 dir_include_pkg = dir_include_pkg / pkg
514 dir_include_pkg_rel = pkg
517 dir_man = get_option('mandir')
519 # FIXME: These used to be separately configurable - worth adding?
520 dir_doc = get_option('datadir') / 'doc'
521 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
522 dir_doc = dir_doc / pkg
524 dir_doc_html = dir_doc / 'html'
526 dir_locale = get_option('localedir')
530 dir_bitcode = dir_lib_pkg / 'bitcode'
531 dir_include_internal = dir_include_pkg / 'internal'
532 dir_include_server = dir_include_pkg / 'server'
533 dir_include_extension = dir_include_server / 'extension'
534 dir_data_extension = dir_data / 'extension'
535 dir_doc_extension = dir_doc / 'extension'
539 ###############################################################
540 # Search paths, preparation for compiler tests
542 # NB: Arguments added later are not automatically used for subsequent
543 # configuration-time checks (so they are more isolated). If they should be
544 # used, they need to be added to test_c_args as well.
545 ###############################################################
547 postgres_inc = [include_directories(postgres_inc_d)]
548 test_lib_d = postgres_lib_d
549 test_c_args = cppflags + cflags
553 ###############################################################
555 ###############################################################
557 bsd_authopt = get_option('bsd_auth')
558 bsd_auth = not_found_dep
559 if cc.check_header('bsd_auth.h', required: bsd_authopt,
560 args: test_c_args, include_directories: postgres_inc)
561 cdata.set('USE_BSD_AUTH', 1)
562 bsd_auth = declare_dependency()
567 ###############################################################
570 # For now don't search for DNSServiceRegister in a library - only Apple's
571 # Bonjour implementation, which is always linked, works.
572 ###############################################################
574 bonjouropt = get_option('bonjour')
575 bonjour = not_found_dep
576 if cc.check_header('dns_sd.h', required: bonjouropt,
577 args: test_c_args, include_directories: postgres_inc) and \
578 cc.has_function('DNSServiceRegister',
579 args: test_c_args, include_directories: postgres_inc)
580 cdata.set('USE_BONJOUR', 1)
581 bonjour = declare_dependency()
586 ###############################################################
587 # Option: docs in HTML and man page format
588 ###############################################################
590 docs_opt = get_option('docs')
591 docs_dep = not_found_dep
592 if not docs_opt.disabled()
593 if xmllint_bin.found() and xsltproc_bin.found()
594 docs_dep = declare_dependency()
595 elif docs_opt.enabled()
596 error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
602 ###############################################################
603 # Option: docs in PDF format
604 ###############################################################
606 docs_pdf_opt = get_option('docs_pdf')
607 docs_pdf_dep = not_found_dep
608 if not docs_pdf_opt.disabled()
609 fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
610 if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
611 docs_pdf_dep = declare_dependency()
612 elif docs_pdf_opt.enabled()
613 error('missing required tools for docs in PDF format')
619 ###############################################################
621 ###############################################################
623 gssapiopt = get_option('gssapi')
626 if not gssapiopt.disabled()
627 gssapi = dependency('krb5-gssapi', required: false)
628 have_gssapi = gssapi.found()
631 gssapi_deps = [gssapi]
633 # Hardcoded lookup for gssapi. This is necessary as gssapi on windows does
634 # not install neither pkg-config nor cmake dependency information.
635 if host_system == 'windows'
636 is_64 = cc.sizeof('void *', args: test_c_args) == 8
638 gssapi_search_libs = ['gssapi64', 'krb5_64', 'comerr64']
640 gssapi_search_libs = ['gssapi32', 'krb5_32', 'comerr32']
643 gssapi_search_libs = ['gssapi_krb5']
647 foreach libname : gssapi_search_libs
648 lib = cc.find_library(libname, dirs: test_lib_d, required: false)
656 # Meson before 0.57.0 did not support using check_header() etc with
657 # declare_dependency(). Thus the tests below use the library looked up
658 # above. Once we require a newer meson version, we can simplify.
659 gssapi = declare_dependency(dependencies: gssapi_deps)
664 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi_deps, required: false,
665 args: test_c_args, include_directories: postgres_inc)
666 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
667 elif cc.check_header('gssapi.h', dependencies: gssapi_deps, required: gssapiopt,
668 args: test_c_args, include_directories: postgres_inc)
669 cdata.set('HAVE_GSSAPI_H', 1)
675 elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi_deps, required: false,
676 args: test_c_args, include_directories: postgres_inc)
677 cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
678 elif cc.check_header('gssapi_ext.h', dependencies: gssapi_deps, required: gssapiopt,
679 args: test_c_args, include_directories: postgres_inc)
680 cdata.set('HAVE_GSSAPI_EXT_H', 1)
686 elif cc.has_function('gss_store_cred_into', dependencies: gssapi_deps,
687 args: test_c_args, include_directories: postgres_inc)
688 cdata.set('ENABLE_GSS', 1)
690 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
691 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
692 elif gssapiopt.enabled()
693 error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
698 if not have_gssapi and gssapiopt.enabled()
699 error('dependency lookup for gssapi failed')
704 gssapi = not_found_dep
709 ###############################################################
711 ###############################################################
713 ldapopt = get_option('ldap')
714 if ldapopt.disabled()
716 ldap_r = not_found_dep
717 elif host_system == 'windows'
718 ldap = cc.find_library('wldap32', required: ldapopt)
721 # macos framework dependency is buggy for ldap (one can argue whether it's
722 # Apple's or meson's fault), leading to an endless recursion with ldap.h
723 # including itself. See https://github.com/mesonbuild/meson/issues/10002
724 # Luckily we only need pkg-config support, so the workaround isn't
726 ldap = dependency('ldap', method: 'pkg-config', required: false)
729 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
732 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
733 has_headers: 'ldap.h', header_include_directories: postgres_inc)
735 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
736 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
737 # library from a separate OpenLDAP installation). The most reliable
738 # way to check that is to check for a function introduced in 2.5.
740 # don't have ldap, we shouldn't check for ldap_r
741 elif cc.has_function('ldap_verify_credentials',
742 dependencies: ldap, args: test_c_args)
743 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
746 # Use ldap_r for FE if available, else assume ldap is thread-safe.
747 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
748 has_headers: 'ldap.h', header_include_directories: postgres_inc)
749 if not ldap_r.found()
752 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
753 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
756 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
757 # process. Check for OpenLDAP versions known not to tolerate doing so;
758 # assume non-OpenLDAP implementations are safe. The dblink test suite
759 # exercises the hazardous interaction directly.
760 compat_test_code = '''
762 #if !defined(LDAP_VENDOR_VERSION) || \
763 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
764 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
768 if not cc.compiles(compat_test_code,
769 name: 'LDAP implementation compatible',
770 dependencies: ldap, args: test_c_args)
772 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
773 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
774 *** also uses LDAP will crash on exit.''')
779 if ldap.found() and cc.has_function('ldap_initialize',
780 dependencies: ldap, args: test_c_args)
781 cdata.set('HAVE_LDAP_INITIALIZE', 1)
786 assert(ldap_r.found())
787 cdata.set('USE_LDAP', 1)
789 assert(not ldap_r.found())
794 ###############################################################
796 ###############################################################
798 llvmopt = get_option('llvm')
800 if add_languages('cpp', required: llvmopt, native: false)
801 llvm = dependency('llvm', version: '>=14', method: 'config-tool', required: llvmopt)
805 cdata.set('USE_LLVM', 1)
807 cpp = meson.get_compiler('cpp')
809 llvm_binpath = llvm.get_variable(configtool: 'bindir')
811 ccache = find_program('ccache', native: true, required: false)
813 # Some distros put LLVM and clang in different paths, so fallback to
814 # find via PATH, too.
815 clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
818 message('llvm requires a C++ compiler')
823 ###############################################################
825 ###############################################################
827 icuopt = get_option('icu')
828 if not icuopt.disabled()
829 icu = dependency('icu-uc', required: false)
831 icu_i18n = dependency('icu-i18n', required: true)
834 # Unfortunately the dependency is named differently with cmake
835 if not icu.found() # combine with above once meson 0.60.0 is required
836 icu = dependency('ICU', required: icuopt,
837 components: ['uc'], modules: ['ICU::uc'], method: 'cmake')
839 icu_i18n = dependency('ICU', required: true,
840 components: ['i18n'], modules: ['ICU::i18n'])
845 cdata.set('USE_ICU', 1)
847 icu_i18n = not_found_dep
852 icu_i18n = not_found_dep
857 ###############################################################
859 ###############################################################
861 libxmlopt = get_option('libxml')
862 if not libxmlopt.disabled()
863 libxml = dependency('libxml-2.0', required: false, version: '>= 2.6.23')
864 # Unfortunately the dependency is named differently with cmake
865 if not libxml.found() # combine with above once meson 0.60.0 is required
866 libxml = dependency('LibXml2', required: libxmlopt, version: '>= 2.6.23',
871 cdata.set('USE_LIBXML', 1)
874 libxml = not_found_dep
879 ###############################################################
881 ###############################################################
883 libxsltopt = get_option('libxslt')
884 if not libxsltopt.disabled()
885 libxslt = dependency('libxslt', required: false)
886 # Unfortunately the dependency is named differently with cmake
887 if not libxslt.found() # combine with above once meson 0.60.0 is required
888 libxslt = dependency('LibXslt', required: libxsltopt, method: 'cmake')
892 cdata.set('USE_LIBXSLT', 1)
895 libxslt = not_found_dep
900 ###############################################################
902 ###############################################################
904 lz4opt = get_option('lz4')
905 if not lz4opt.disabled()
906 lz4 = dependency('liblz4', required: false)
907 # Unfortunately the dependency is named differently with cmake
908 if not lz4.found() # combine with above once meson 0.60.0 is required
909 lz4 = dependency('lz4', required: lz4opt,
910 method: 'cmake', modules: ['LZ4::lz4_shared'],
915 cdata.set('USE_LZ4', 1)
916 cdata.set('HAVE_LIBLZ4', 1)
925 ###############################################################
926 # Library: Tcl (for pltcl)
928 # NB: tclConfig.sh is used in autoconf build for getting
929 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
930 # variables. For now we have not seen a need to copy
931 # that behaviour to the meson build.
932 ###############################################################
934 tclopt = get_option('pltcl')
935 tcl_version = get_option('tcl_version')
936 tcl_dep = not_found_dep
937 if not tclopt.disabled()
940 tcl_dep = dependency(tcl_version, required: false)
942 if not tcl_dep.found()
943 tcl_dep = cc.find_library(tcl_version,
948 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
949 tcl_dep = not_found_dep
955 ###############################################################
957 ###############################################################
959 pamopt = get_option('pam')
960 if not pamopt.disabled()
961 pam = dependency('pam', required: false)
964 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
968 pam_header_found = false
970 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
971 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
972 args: test_c_args, include_directories: postgres_inc)
973 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
974 pam_header_found = true
975 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
976 args: test_c_args, include_directories: postgres_inc)
977 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
978 pam_header_found = true
982 cdata.set('USE_PAM', 1)
993 ###############################################################
994 # Library: Perl (for plperl)
995 ###############################################################
997 perlopt = get_option('plperl')
998 perl_dep = not_found_dep
999 if not perlopt.disabled()
1000 perl_may_work = true
1002 # First verify that perl has the necessary dependencies installed
1003 perl_mods = run_command(
1005 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
1008 if perl_mods.returncode() != 0
1009 perl_may_work = false
1010 perl_msg = 'perl installation does not have the required modules'
1013 # Then inquire perl about its configuration
1015 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
1016 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
1017 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
1018 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
1019 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
1021 perl_inc_dir = '@0@/CORE'.format(archlibexp)
1023 if perlversion.version_compare('< 5.14')
1024 perl_may_work = false
1025 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
1026 elif useshrplib != 'true'
1027 perl_may_work = false
1028 perl_msg = 'need a shared perl'
1033 # On most platforms, archlibexp is also where the Perl include files live ...
1034 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
1035 # ... but on newer macOS versions, we must use -iwithsysroot to look
1037 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
1038 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
1039 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
1042 # check compiler finds header
1043 if not cc.has_header('perl.h', required: false,
1044 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
1045 perl_may_work = false
1046 perl_msg = 'missing perl.h'
1051 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
1053 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
1054 foreach flag : perl_ccflags_r.split(' ')
1055 if flag.startswith('-D') and \
1056 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
1057 perl_ccflags += flag
1061 if host_system == 'windows'
1062 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
1064 if cc.get_id() == 'msvc'
1065 # prevent binary mismatch between MSVC built plperl and Strawberry or
1066 # msys ucrt perl libraries
1067 perl_v = run_command(perl, '-V').stdout()
1068 if not perl_v.contains('USE_THREAD_SAFE_LOCALE')
1069 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
1074 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
1075 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
1077 # We are after Embed's ldopts, but without the subset mentioned in
1078 # Config's ccdlflags and ldflags. (Those are the choices of those who
1079 # built the Perl installation, which are not necessarily appropriate
1080 # for building PostgreSQL.)
1081 perl_ldopts = run_command(perl, '-e', '''
1082 use ExtUtils::Embed;
1083 use Text::ParseWords;
1084 # tell perl to suppress including these in ldopts
1085 *ExtUtils::Embed::_ldflags =*ExtUtils::Embed::_ccdlflags = sub { return ""; };
1086 # adding an argument to ldopts makes it return a value instead of printing
1087 # print one of these per line so splitting will preserve spaces in file names.
1088 # shellwords eats backslashes, so we need to escape them.
1089 (my $opts = ldopts(undef)) =~ s!\\!\\\\!g;
1090 print "$_\n" foreach shellwords($opts);
1092 check: true).stdout().strip().split('\n')
1094 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1096 perl_dep_int = declare_dependency(
1097 compile_args: perl_ccflags,
1098 link_args: perl_ldopts,
1099 version: perlversion,
1102 # While we're at it, check that we can link to libperl.
1103 # On most platforms, if perl.h is there then libperl.so will be too, but
1104 # at this writing Debian packages them separately.
1105 perl_link_test = '''
1108 #define __inline__ inline
1116 if not cc.links(perl_link_test, name: 'libperl',
1117 args: test_c_args + perl_ccflags + perl_ldopts,
1118 include_directories: postgres_inc)
1119 perl_may_work = false
1120 perl_msg = 'missing libperl'
1123 endif # perl_may_work
1126 perl_dep = perl_dep_int
1128 if perlopt.enabled()
1129 error('dependency plperl failed: @0@'.format(perl_msg))
1131 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1138 ###############################################################
1139 # Library: Python (for plpython)
1140 ###############################################################
1142 pyopt = get_option('plpython')
1143 python3_dep = not_found_dep
1144 if not pyopt.disabled()
1145 pm = import('python')
1146 python3_inst = pm.find_installation(python.path(), required: pyopt)
1147 if python3_inst.found()
1148 python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1149 # Remove this check after we depend on Meson >= 1.1.0
1150 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1151 python3_dep = not_found_dep
1158 ###############################################################
1160 ###############################################################
1162 if not get_option('readline').disabled()
1163 libedit_preferred = get_option('libedit_preferred')
1164 # Set the order of readline dependencies.
1165 # cc.find_library breaks and throws on the first dependency which
1166 # is marked as required=true and can't be found. Thus, we only mark
1167 # the last dependency to look up as required, to not throw too early.
1168 check_readline_deps = [
1170 'name': libedit_preferred ? 'libedit' : 'readline',
1174 'name': libedit_preferred ? 'readline' : 'libedit',
1175 'required': get_option('readline')
1179 foreach readline_dep : check_readline_deps
1180 readline = dependency(readline_dep['name'], required: false)
1181 if not readline.found()
1182 readline = cc.find_library(readline_dep['name'],
1183 required: readline_dep['required'],
1192 cdata.set('HAVE_LIBREADLINE', 1)
1195 'header_prefix': 'editline/',
1196 'flag_prefix': 'EDITLINE_',
1199 'header_prefix': 'readline/',
1200 'flag_prefix': 'READLINE_',
1203 'header_prefix': '',
1207 # Set the order of prefixes
1208 prefixes = libedit_preferred ? \
1209 [editline_prefix, default_prefix, readline_prefix] : \
1210 [readline_prefix, default_prefix, editline_prefix]
1212 at_least_one_header_found = false
1213 foreach header : ['history', 'readline']
1215 foreach prefix : prefixes
1216 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1217 # Check history.h and readline.h
1218 if not is_found and cc.has_header(header_file,
1219 args: test_c_args, include_directories: postgres_inc,
1220 dependencies: [readline], required: false)
1221 if header == 'readline'
1222 readline_h = header_file
1224 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1226 at_least_one_header_found = true
1231 if not at_least_one_header_found
1232 error('''readline header not found
1233 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1234 failure. It is possible the compiler isn't looking in the proper directory.
1235 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1240 'history_truncate_file',
1241 'rl_completion_matches',
1242 'rl_filename_completion_function',
1243 'rl_reset_screen_size',
1247 foreach func : check_funcs
1248 found = cc.has_function(func, dependencies: [readline],
1249 args: test_c_args, include_directories: postgres_inc)
1250 cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1254 'rl_completion_suppress_quote',
1255 'rl_filename_quote_characters',
1256 'rl_filename_quoting_function',
1259 foreach var : check_vars
1260 cdata.set('HAVE_' + var.to_upper(),
1261 cc.has_header_symbol(readline_h, var,
1262 args: test_c_args, include_directories: postgres_inc,
1263 prefix: '#include <stdio.h>',
1264 dependencies: [readline]) ? 1 : false)
1267 # If found via cc.find_library() ensure headers are found when using the
1268 # dependency. On meson < 0.57 one cannot do compiler checks using the
1269 # dependency returned by declare_dependency(), so we can't do this above.
1270 if readline.type_name() == 'library'
1271 readline = declare_dependency(dependencies: readline,
1272 include_directories: postgres_inc)
1275 # On windows with mingw readline requires auto-import to successfully
1276 # link, as the headers don't use declspec(dllimport)
1277 if host_system == 'windows' and cc.get_id() != 'msvc'
1278 readline = declare_dependency(dependencies: readline,
1279 link_args: '-Wl,--enable-auto-import')
1283 # XXX: Figure out whether to implement mingw warning equivalent
1285 readline = not_found_dep
1290 ###############################################################
1292 ###############################################################
1294 selinux = not_found_dep
1295 selinuxopt = get_option('selinux')
1296 if meson.version().version_compare('>=0.59')
1297 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1299 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1300 cdata.set('HAVE_LIBSELINUX',
1301 selinux.found() ? 1 : false)
1305 ###############################################################
1307 ###############################################################
1309 systemd = not_found_dep
1310 systemdopt = get_option('systemd')
1311 if meson.version().version_compare('>=0.59')
1312 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1314 systemd = dependency('libsystemd', required: systemdopt)
1315 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1319 ###############################################################
1321 ###############################################################
1324 ssl_library = 'none'
1325 sslopt = get_option('ssl')
1327 if sslopt == 'auto' and auto_features.disabled()
1331 if sslopt in ['auto', 'openssl']
1332 openssl_required = (sslopt == 'openssl')
1334 # Try to find openssl via pkg-config et al, if that doesn't work
1335 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1336 # the library names that we know about.
1338 # via pkg-config et al
1339 ssl = dependency('openssl', required: false)
1340 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1341 # we pass cc.find_library() results if necessary
1344 # via library + headers
1346 ssl_lib = cc.find_library('ssl',
1348 header_include_directories: postgres_inc,
1349 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1350 required: openssl_required)
1351 crypto_lib = cc.find_library('crypto',
1353 required: openssl_required)
1354 if ssl_lib.found() and crypto_lib.found()
1355 ssl_int = [ssl_lib, crypto_lib]
1356 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1358 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1359 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1367 ['CRYPTO_new_ex_data', {'required': true}],
1368 ['SSL_new', {'required': true}],
1370 # Functions introduced in OpenSSL 1.1.1.
1371 ['SSL_CTX_set_ciphersuites', {'required': true}],
1373 # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1374 ['SSL_CTX_set_cert_cb'],
1376 # Function introduced in OpenSSL 1.1.1, not in LibreSSL.
1377 ['X509_get_signature_info'],
1378 ['SSL_CTX_set_num_tickets'],
1381 are_openssl_funcs_complete = true
1382 foreach c : check_funcs
1384 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1385 required = c.get(1, {}).get('required', false)
1386 if required and not val
1387 are_openssl_funcs_complete = false
1389 error('openssl function @0@ is required'.format(func))
1393 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1397 if are_openssl_funcs_complete
1398 cdata.set('USE_OPENSSL', 1,
1399 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1400 cdata.set('OPENSSL_API_COMPAT', '0x10101000L',
1401 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1402 ssl_library = 'openssl'
1409 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1410 error('no SSL library found')
1415 ###############################################################
1417 ###############################################################
1419 uuidopt = get_option('uuid')
1420 if uuidopt != 'none'
1421 uuidname = uuidopt.to_upper()
1422 if uuidopt == 'e2fs'
1423 uuid = dependency('uuid', required: true)
1424 uuidfunc = 'uuid_generate'
1425 uuidheader = 'uuid/uuid.h'
1426 elif uuidopt == 'bsd'
1427 # libc should have uuid function
1428 uuid = declare_dependency()
1429 uuidfunc = 'uuid_to_string'
1430 uuidheader = 'uuid.h'
1431 elif uuidopt == 'ossp'
1432 # In upstream, the package and library is called just 'uuid', but many
1433 # distros change it to 'ossp-uuid'.
1434 uuid = dependency('ossp-uuid', 'uuid', required: false)
1435 uuidfunc = 'uuid_export'
1436 uuidheader = 'uuid.h'
1438 # Hardcoded lookup for ossp-uuid. This is necessary as ossp-uuid on
1439 # windows installs neither a pkg-config nor a cmake dependency
1440 # information. Nor is there another supported uuid implementation
1441 # available on windows.
1443 uuid = cc.find_library('ossp-uuid',
1444 required: false, dirs: test_lib_d,
1445 has_headers: uuidheader, header_include_directories: postgres_inc)
1448 uuid = cc.find_library('uuid',
1449 required: true, dirs: test_lib_d,
1450 has_headers: uuidheader, header_include_directories: postgres_inc)
1453 error('unknown uuid build option value: @0@'.format(uuidopt))
1456 if not cc.has_header_symbol(uuidheader, uuidfunc,
1458 include_directories: postgres_inc,
1460 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1462 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1464 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1465 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1467 uuid = not_found_dep
1472 ###############################################################
1474 ###############################################################
1476 zlibopt = get_option('zlib')
1477 zlib = not_found_dep
1478 if not zlibopt.disabled()
1479 zlib_t = dependency('zlib', required: zlibopt)
1481 if zlib_t.type_name() == 'internal'
1482 # if fallback was used, we don't need to test if headers are present (they
1483 # aren't built yet, so we can't test)
1485 elif not zlib_t.found()
1486 warning('did not find zlib')
1487 elif not cc.has_header('zlib.h',
1488 args: test_c_args, include_directories: postgres_inc,
1489 dependencies: [zlib_t], required: zlibopt)
1490 warning('zlib header not found')
1496 cdata.set('HAVE_LIBZ', 1)
1502 ###############################################################
1503 # Library: tap test dependencies
1504 ###############################################################
1506 # Check whether tap tests are enabled or not
1507 tap_tests_enabled = false
1508 tapopt = get_option('tap_tests')
1509 if not tapopt.disabled()
1510 # Checking for perl modules for tap tests
1511 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1512 if perl_ipc_run_check.returncode() != 0
1513 message(perl_ipc_run_check.stderr().strip())
1515 error('Additional Perl modules are required to run TAP tests.')
1517 warning('Additional Perl modules are required to run TAP tests.')
1520 tap_tests_enabled = true
1526 ###############################################################
1528 ###############################################################
1530 zstdopt = get_option('zstd')
1531 if not zstdopt.disabled()
1532 zstd = dependency('libzstd', required: false, version: '>=1.4.0')
1533 # Unfortunately the dependency is named differently with cmake
1534 if not zstd.found() # combine with above once meson 0.60.0 is required
1535 zstd = dependency('zstd', required: zstdopt, version: '>=1.4.0',
1536 method: 'cmake', modules: ['zstd::libzstd_shared'])
1540 cdata.set('USE_ZSTD', 1)
1541 cdata.set('HAVE_LIBZSTD', 1)
1545 zstd = not_found_dep
1550 ###############################################################
1552 ###############################################################
1554 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1555 # unnecessarily, because we optionally rely on newer features.
1557 #include <stdbool.h>
1558 #include <complex.h>
1560 #include <inttypes.h>
1562 struct named_init_test {
1567 extern void structfunc(struct named_init_test);
1569 int main(int argc, char **argv)
1571 struct named_init_test nit = {
1576 for (int loop_var = 0; loop_var < 3; loop_var++)
1581 structfunc((struct named_init_test){1, 0});
1587 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1588 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1589 args: test_c_args + ['-std=c99'])
1590 test_c_args += '-std=c99'
1591 cflags += '-std=c99'
1593 error('C compiler does not support C99')
1597 if host_machine.endian() == 'big'
1598 cdata.set('WORDS_BIGENDIAN', 1)
1601 # Determine memory alignment requirements for the basic C data types.
1603 alignof_types = ['short', 'int', 'long', 'double']
1604 foreach t : alignof_types
1605 align = cc.alignment(t, args: test_c_args)
1606 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1609 # Compute maximum alignment of any basic type.
1611 # We require 'double' to have the strictest alignment among the basic types,
1612 # because otherwise the C ABI might impose 8-byte alignment on some of the
1613 # other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
1614 # cause a mismatch between the tuple layout and the C struct layout of a
1615 # catalog tuple. We used to carefully order catalog columns such that any
1616 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1617 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1618 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1620 # We assume without checking that int64_t's alignment is at least as strong
1621 # as long, char, short, or int. Note that we intentionally do not consider
1622 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1623 # would be too much of a penalty for disk and memory space.
1624 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1625 if cc.alignment('int64_t', args: test_c_args, prefix: '#include <stdint.h>') > alignof_double
1626 error('alignment of int64_t is greater than the alignment of double')
1628 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1630 cdata.set('SIZEOF_LONG', cc.sizeof('long', args: test_c_args))
1631 cdata.set('SIZEOF_LONG_LONG', cc.sizeof('long long', args: test_c_args))
1632 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1633 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1636 # Check if __int128 is a working 128 bit integer type, and if so
1637 # define PG_INT128_TYPE to that typename.
1639 # This currently only detects a GCC/clang extension, but support for other
1640 # environments may be added in the future.
1642 # For the moment we only test for support for 128bit math; support for
1643 # 128bit literals and snprintf is not required.
1646 * We don't actually run this test, just link it to verify that any support
1647 * functions needed for __int128 are present.
1649 * These are globals to discourage the compiler from folding all the
1650 * arithmetic tests down to compile-time constants. We do not have
1651 * convenient support for 128bit literals at this point...
1653 __int128 a = 48828125;
1654 __int128 b = 97656250;
1659 a = (a << 12) + 1; /* 200000000001 */
1660 b = (b << 12) + 5; /* 400000000005 */
1661 /* try the most relevant arithmetic ops */
1664 /* must use the results, else compiler may optimize arithmetic away */
1670 buggy_int128 = false
1672 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1673 # If not cross-compiling, we can test for bugs and disable use of __int128
1674 # with buggy compilers. If cross-compiling, hope for the best.
1675 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1676 if not meson.is_cross_build()
1678 /* This must match the corresponding code in c.h: */
1679 #if defined(__GNUC__) || defined(__SUNPRO_C)
1680 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1681 #elif defined(_MSC_VER)
1682 #define pg_attribute_aligned(a) __declspec(align(a))
1684 typedef __int128 int128a
1685 #if defined(pg_attribute_aligned)
1686 pg_attribute_aligned(8)
1691 void pass_by_val(void *buffer, int128a par) { holder = par; }
1695 long int i64 = 97656225L << 12;
1697 pass_by_val(main, (int128a) i64);
1701 name: '__int128 alignment bug',
1703 assert(r.compiled())
1704 if r.returncode() != 0
1706 message('__int128 support present but buggy and thus disabled')
1711 cdata.set('PG_INT128_TYPE', '__int128')
1712 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1717 # Check if the C compiler knows computed gotos (gcc extension, also
1718 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1720 # Checking whether computed gotos are supported syntax-wise ought to
1721 # be enough, as the syntax is otherwise illegal.
1723 static inline int foo(void)
1725 void *labeladdrs[] = {&&my_label};
1726 goto *labeladdrs[0];
1730 name: 'computed goto',
1732 cdata.set('HAVE_COMPUTED_GOTO', 1)
1736 # Check if the C compiler understands _Static_assert(),
1737 # and define HAVE__STATIC_ASSERT if so.
1739 # We actually check the syntax ({ _Static_assert(...) }), because we need
1740 # gcc-style compound expressions to be able to wrap the thing into macros.
1742 int main(int arg, char **argv)
1744 ({ _Static_assert(1, "foo"); });
1747 name: '_Static_assert',
1749 cdata.set('HAVE__STATIC_ASSERT', 1)
1753 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1754 # warning for each use of %m.
1755 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1757 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1758 static void call_log(void)
1760 emit_log(0, "error: %s: %m", "foo");
1763 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1764 foreach a : printf_attributes
1765 if cc.compiles(testsrc.format(a),
1766 args: test_c_args + attrib_error_args, name: 'format ' + a)
1767 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1773 if cc.has_function_attribute('visibility:default') and \
1774 cc.has_function_attribute('visibility:hidden')
1775 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1777 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1778 # inlineshidden to C code as well... And either way, we want to put these
1779 # flags into exported files (pgxs, .pc files).
1780 cflags_mod += '-fvisibility=hidden'
1781 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1782 ldflags_mod += '-fvisibility=hidden'
1786 # Check if various builtins exist. Some builtins are tested separately,
1787 # because we want to test something more complicated than the generic case.
1800 foreach builtin : builtins
1801 fname = '__builtin_@0@'.format(builtin)
1802 if cc.has_function(fname, args: test_c_args)
1803 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1808 # Check if the C compiler understands __builtin_types_compatible_p,
1809 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1811 # We check usage with __typeof__, though it's unlikely any compiler would
1812 # have the former and not the latter.
1815 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1817 name: '__builtin_types_compatible_p',
1819 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1823 # Check if the C compiler understands __builtin_$op_overflow(),
1824 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1826 # Check for the most complicated case, 64 bit multiplication, as a
1827 # proxy for all of the operations. To detect the case where the compiler
1828 # knows the function but library support is missing, we must link not just
1829 # compile, and store the results in global variables so the compiler doesn't
1830 # optimize away the call.
1839 return __builtin_mul_overflow(a, b, &result);
1841 name: '__builtin_mul_overflow',
1843 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1847 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1848 # here. To prevent problems due to two detection methods working, stop
1849 # checking after one.
1852 int main(int arg, char **argv)
1854 unsigned int exx[4] = {0, 0, 0, 0};
1855 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1857 ''', name: '__get_cpuid',
1859 cdata.set('HAVE__GET_CPUID', 1)
1862 int main(int arg, char **argv)
1864 unsigned int exx[4] = {0, 0, 0, 0};
1867 ''', name: '__cpuid',
1869 cdata.set('HAVE__CPUID', 1)
1873 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1876 int main(int arg, char **argv)
1878 unsigned int exx[4] = {0, 0, 0, 0};
1879 __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1881 ''', name: '__get_cpuid_count',
1883 cdata.set('HAVE__GET_CPUID_COUNT', 1)
1886 int main(int arg, char **argv)
1888 unsigned int exx[4] = {0, 0, 0, 0};
1889 __cpuidex(exx, 7, 0);
1891 ''', name: '__cpuidex',
1893 cdata.set('HAVE__CPUIDEX', 1)
1897 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1898 # versions of clang do not understand -fexcess-precision=standard, the use of
1899 # x87 floating point operations leads to problems like isinf possibly returning
1900 # false for a value that is infinite when converted from the 80bit register to
1901 # the 8byte memory representation.
1903 # Only perform the test if the compiler doesn't understand
1904 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1906 if '-fexcess-precision=standard' not in cflags
1907 if not cc.compiles('''
1908 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1911 name: '', args: test_c_args)
1912 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1918 ###############################################################
1920 ###############################################################
1922 common_functional_flags = [
1923 # Disable strict-aliasing rules; needed for gcc 3.3+
1924 '-fno-strict-aliasing',
1925 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1927 '-fexcess-precision=standard',
1930 cflags += cc.get_supported_arguments(common_functional_flags)
1932 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1935 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1936 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1938 common_warning_flags = [
1939 '-Wmissing-prototypes',
1941 # Really don't want VLAs to be used in our dialect of C
1943 # On macOS, complain about usage of symbols newer than the deployment target
1944 '-Werror=unguarded-availability-new',
1946 '-Wmissing-format-attribute',
1947 '-Wimplicit-fallthrough=3',
1948 '-Wcast-function-type',
1949 '-Wshadow=compatible-local',
1950 # This was included in -Wall/-Wformat in older GCC versions
1951 '-Wformat-security',
1954 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1956 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1959 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1960 # the result for them
1961 cflags_no_decl_after_statement = []
1962 if cc.has_argument('-Wdeclaration-after-statement')
1963 cflags_warn += '-Wdeclaration-after-statement'
1964 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1967 # Some code is not clean for -Wmissing-variable-declarations, so we
1968 # make the "no" option available. Also, while clang supports this
1969 # option for C++, gcc does not, so for consistency, leave it off for
1971 cflags_no_missing_var_decls = []
1972 if cc.has_argument('-Wmissing-variable-declarations')
1973 cflags_warn += '-Wmissing-variable-declarations'
1974 cflags_no_missing_var_decls += '-Wno-missing-variable-declarations'
1978 # The following tests want to suppress various unhelpful warnings by adding
1979 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1980 # switches, so we have to test for the positive form and if that works,
1981 # add the negative form.
1983 negative_warning_flags = [
1984 # Suppress clang's unhelpful unused-command-line-argument warnings.
1985 'unused-command-line-argument',
1987 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1988 # of warnings when building plperl because of usages in the Perl headers.
1989 'compound-token-split-by-macro',
1991 # Similarly disable useless truncation warnings from gcc 8+
1992 'format-truncation',
1993 'stringop-truncation',
1995 # Suppress clang 16's strict warnings about function casts
1996 'cast-function-type-strict',
1998 # To make warning_level=2 / -Wextra work, we'd need at least the following
2000 # 'missing-field-initializers',
2002 # 'unused-parameter',
2005 foreach w : negative_warning_flags
2006 if cc.has_argument('-W' + w)
2007 cflags_warn += '-Wno-' + w
2009 if llvm.found() and cpp.has_argument('-W' + w)
2010 cxxflags_warn += '-Wno-' + w
2015 if cc.get_id() == 'msvc'
2017 '/wd4018', # signed/unsigned mismatch
2018 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
2019 '/wd4273', # inconsistent DLL linkage
2020 '/wd4101', # unreferenced local variable
2021 '/wd4102', # unreferenced label
2022 '/wd4090', # different 'modifier' qualifiers
2023 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
2031 '/D_CRT_SECURE_NO_DEPRECATE',
2032 '/D_CRT_NONSTDC_NO_DEPRECATE',
2035 # We never need export libraries. As link.exe reports their creation, they
2036 # are unnecessarily noisy. Similarly, we don't need import library for
2037 # modules, we only import them dynamically, and they're also noisy.
2039 ldflags_mod += '/NOIMPLIB'
2043 # Compute flags that are built into Meson. We need these to
2044 # substitute into Makefile.global and for pg_config. We only compute
2045 # the flags for Unix-style compilers, since that's the only style that
2046 # would use Makefile.global or pg_config.
2048 # We don't use get_option('warning_level') here, because the other
2049 # warning levels are not useful with PostgreSQL source code.
2050 common_builtin_flags = ['-Wall']
2052 if get_option('debug')
2053 common_builtin_flags += ['-g']
2056 optimization = get_option('optimization')
2057 if optimization == '0'
2058 common_builtin_flags += ['-O0']
2059 elif optimization == '1'
2060 common_builtin_flags += ['-O1']
2061 elif optimization == '2'
2062 common_builtin_flags += ['-O2']
2063 elif optimization == '3'
2064 common_builtin_flags += ['-O3']
2065 elif optimization == 's'
2066 common_builtin_flags += ['-Os']
2069 cflags_builtin = cc.get_supported_arguments(common_builtin_flags)
2071 cxxflags_builtin = cpp.get_supported_arguments(common_builtin_flags)
2076 ###############################################################
2078 ###############################################################
2081 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2082 'desc': '__sync_lock_test_and_set(char)',
2085 __sync_lock_test_and_set(&lock, 1);
2086 __sync_lock_release(&lock);'''},
2088 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2089 'desc': '__sync_lock_test_and_set(int32)',
2092 __sync_lock_test_and_set(&lock, 1);
2093 __sync_lock_release(&lock);'''},
2095 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2096 'desc': '__sync_val_compare_and_swap(int32)',
2099 __sync_val_compare_and_swap(&val, 0, 37);'''},
2101 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2102 'desc': '__sync_val_compare_and_swap(int64)',
2105 __sync_val_compare_and_swap(&val, 0, 37);'''},
2107 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2108 'desc': ' __atomic_compare_exchange_n(int32)',
2112 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2114 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2115 'desc': ' __atomic_compare_exchange_n(int64)',
2119 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2122 foreach check : atomic_checks
2128 }'''.format(check['test'])
2130 cdata.set(check['name'],
2132 name: check['desc'],
2133 args: test_c_args) ? 1 : false
2138 ###############################################################
2139 # Check for the availability of XSAVE intrinsics.
2140 ###############################################################
2142 if host_cpu == 'x86' or host_cpu == 'x86_64'
2145 #include <immintrin.h>
2147 #if defined(__has_attribute) && __has_attribute (target)
2148 __attribute__((target("xsave")))
2152 return _xgetbv(0) & 0xe0;
2156 if cc.links(prog, name: 'XSAVE intrinsics', args: test_c_args)
2157 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2163 ###############################################################
2164 # Check for the availability of AVX-512 popcount intrinsics.
2165 ###############################################################
2167 if host_cpu == 'x86_64'
2170 #include <immintrin.h>
2173 #if defined(__has_attribute) && __has_attribute (target)
2174 __attribute__((target("avx512vpopcntdq,avx512bw")))
2178 const char buf[sizeof(__m512i)];
2180 __m512i accum = _mm512_setzero_si512();
2181 const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2182 const __m512i cnt = _mm512_popcnt_epi64(val);
2183 accum = _mm512_add_epi64(accum, cnt);
2184 popcnt = _mm512_reduce_add_epi64(accum);
2185 /* return computed value, to prevent the above being optimized away */
2190 if cc.links(prog, name: 'AVX-512 popcount', args: test_c_args)
2191 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2197 ###############################################################
2198 # Select CRC-32C implementation.
2200 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2201 # use the special CRC instructions for calculating CRC-32C. If we're not
2202 # targeting such a processor, but we can nevertheless produce code that uses
2203 # the SSE intrinsics, compile both implementations and select which one to use
2204 # at runtime, depending on whether SSE 4.2 is supported by the processor we're
2207 # Similarly, if we are targeting an ARM processor that has the CRC
2208 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2209 # we're not targeting such a processor, but can nevertheless produce code that
2210 # uses the CRC instructions, compile both, and select at runtime.
2212 # Note that we do not use __attribute__((target("..."))) for the ARM CRC
2213 # instructions because until clang 16, using the ARM intrinsics still requires
2214 # special -march flags. Perhaps we can re-evaluate this decision after some
2216 ###############################################################
2218 have_optimized_crc = false
2220 if host_cpu == 'x86' or host_cpu == 'x86_64'
2222 if cc.get_id() == 'msvc'
2223 cdata.set('USE_SSE42_CRC32C', false)
2224 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2225 have_optimized_crc = true
2229 #include <nmmintrin.h>
2231 #if defined(__has_attribute) && __has_attribute (target)
2232 __attribute__((target("sse4.2")))
2236 unsigned int crc = 0;
2237 crc = _mm_crc32_u8(crc, 0);
2238 crc = _mm_crc32_u32(crc, 0);
2239 /* return computed value, to prevent the above being optimized away */
2244 if not cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32',
2246 # Do not use Intel SSE 4.2
2247 elif (cc.get_define('__SSE4_2__') != '')
2248 # Use Intel SSE 4.2 unconditionally.
2249 cdata.set('USE_SSE42_CRC32C', 1)
2250 have_optimized_crc = true
2252 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2253 # the runtime check.
2254 cdata.set('USE_SSE42_CRC32C', false)
2255 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2256 have_optimized_crc = true
2261 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2264 #include <arm_acle.h>
2268 unsigned int crc = 0;
2269 crc = __crc32cb(crc, 0);
2270 crc = __crc32ch(crc, 0);
2271 crc = __crc32cw(crc, 0);
2272 crc = __crc32cd(crc, 0);
2274 /* return computed value, to prevent the above being optimized away */
2279 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2281 # Use ARM CRC Extension unconditionally
2282 cdata.set('USE_ARMV8_CRC32C', 1)
2283 have_optimized_crc = true
2284 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
2285 args: test_c_args + ['-march=armv8-a+crc+simd'])
2286 # Use ARM CRC Extension, with runtime check
2287 cflags_crc += '-march=armv8-a+crc+simd'
2288 cdata.set('USE_ARMV8_CRC32C', false)
2289 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2290 have_optimized_crc = true
2291 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2292 args: test_c_args + ['-march=armv8-a+crc'])
2293 # Use ARM CRC Extension, with runtime check
2294 cflags_crc += '-march=armv8-a+crc'
2295 cdata.set('USE_ARMV8_CRC32C', false)
2296 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2297 have_optimized_crc = true
2300 elif host_cpu == 'loongarch64'
2305 unsigned int crc = 0;
2306 crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2307 crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2308 crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2309 crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2311 /* return computed value, to prevent the above being optimized away */
2316 if cc.links(prog, name: '__builtin_loongarch_crcc_w_b_w, __builtin_loongarch_crcc_w_h_w, __builtin_loongarch_crcc_w_w_w, and __builtin_loongarch_crcc_w_d_w',
2318 # Use LoongArch CRC instruction unconditionally
2319 cdata.set('USE_LOONGARCH_CRC32C', 1)
2320 have_optimized_crc = true
2325 if not have_optimized_crc
2326 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2328 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2333 ###############################################################
2334 # Other CPU specific stuff
2335 ###############################################################
2337 if host_cpu == 'x86_64'
2342 long long x = 1; long long r;
2343 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2345 name: '@0@: popcntq instruction'.format(host_cpu),
2347 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2350 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2351 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2352 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2355 addi(int ra, int si)
2358 if (__builtin_constant_p(si))
2359 __asm__ __volatile__(
2360 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2363 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2365 name: '@0@: "i"(x) when __builtin_constant_p(x)'.format(host_cpu),
2367 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2374 ###############################################################
2375 # Library / OS tests
2376 ###############################################################
2378 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2379 # unnecessary checks over and over, particularly on windows.
2391 'sys/personality.h',
2401 foreach header : header_checks
2402 varname = 'HAVE_' + header.underscorify().to_upper()
2404 # Emulate autoconf behaviour of not-found->undef, found->1
2405 found = cc.has_header(header,
2406 include_directories: postgres_inc, args: test_c_args)
2407 cdata.set(varname, found ? 1 : false,
2408 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2413 ['F_FULLFSYNC', 'fcntl.h'],
2414 ['fdatasync', 'unistd.h'],
2415 ['posix_fadvise', 'fcntl.h'],
2416 ['strlcat', 'string.h'],
2417 ['strlcpy', 'string.h'],
2418 ['strnlen', 'string.h'],
2419 ['strsep', 'string.h'],
2422 # Need to check for function declarations for these functions, because
2423 # checking for library symbols wouldn't handle deployment target
2424 # restrictions on macOS
2426 ['preadv', 'sys/uio.h'],
2427 ['pwritev', 'sys/uio.h'],
2430 # Check presence of some optional LLVM functions.
2433 ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2434 ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2438 foreach c : decl_checks
2442 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2444 found = cc.has_header_symbol(header, func,
2445 args: test_c_args, include_directories: postgres_inc,
2447 cdata.set10(varname, found, description:
2448 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2449 don't.'''.format(func))
2453 if cc.has_type('struct option',
2454 args: test_c_args, include_directories: postgres_inc,
2455 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2456 cdata.set('HAVE_STRUCT_OPTION', 1)
2460 foreach c : ['opterr', 'optreset']
2461 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2470 '''.format(c), name: c, args: test_c_args)
2471 cdata.set(varname, 1)
2473 cdata.set(varname, false)
2477 if cc.has_type('socklen_t',
2478 args: test_c_args, include_directories: postgres_inc,
2480 #include <sys/socket.h>''')
2481 cdata.set('HAVE_SOCKLEN_T', 1)
2484 if cc.has_member('struct sockaddr', 'sa_len',
2485 args: test_c_args, include_directories: postgres_inc,
2487 #include <sys/types.h>
2488 #include <sys/socket.h>''')
2489 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2492 if cc.has_member('struct tm', 'tm_zone',
2493 args: test_c_args, include_directories: postgres_inc,
2495 #include <sys/types.h>
2498 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2503 extern int foo(void);
2506 return timezone / 60;
2509 name: 'global variable `timezone\' exists',
2510 args: test_c_args, include_directories: postgres_inc)
2511 cdata.set('HAVE_INT_TIMEZONE', 1)
2513 cdata.set('HAVE_INT_TIMEZONE', false)
2516 if cc.has_type('union semun',
2518 include_directories: postgres_inc,
2520 #include <sys/types.h>
2521 #include <sys/ipc.h>
2522 #include <sys/sem.h>
2524 cdata.set('HAVE_UNION_SEMUN', 1)
2532 switch (strerror_r(1, buf, sizeof(buf)))
2533 { case 0: break; default: break; }
2536 args: test_c_args, include_directories: postgres_inc)
2537 cdata.set('STRERROR_R_INT', 1)
2539 cdata.set('STRERROR_R_INT', false)
2542 # Check if the C compiler understands typeof or a variant. Define
2543 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2544 foreach kw : ['typeof', '__typeof__']
2555 args: test_c_args, include_directories: postgres_inc)
2557 cdata.set('HAVE_TYPEOF', 1)
2559 cdata.set('typeof', kw)
2567 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2568 # understands, because it conflicts with __declspec(restrict). Therefore we
2569 # define pg_restrict to the appropriate definition, which presumably won't
2572 # We assume C99 support, so we don't need to make this conditional.
2573 cdata.set('pg_restrict', '__restrict')
2576 # Most libraries are included only if they demonstrably provide a function we
2577 # need, but libm is an exception: always include it, because there are too
2578 # many compilers that play cute optimization games that will break probes for
2579 # standard functions such as pow().
2580 os_deps += cc.find_library('m', required: false)
2582 rt_dep = cc.find_library('rt', required: false)
2584 dl_dep = cc.find_library('dl', required: false)
2586 util_dep = cc.find_library('util', required: false)
2588 getopt_dep = cc.find_library('getopt', required: false)
2589 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2590 # Check if we want to replace getopt/getopt_long even if provided by the system
2591 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2592 # so always use our version on Windows
2593 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2594 # (i.e., allow '-' as a flag character), so use our version on those platforms
2595 # - We want to use system's getopt_long() only if the system provides struct
2597 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2598 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2601 execinfo_dep = cc.find_library('execinfo', required: false)
2603 if host_system == 'cygwin'
2604 cygipc_dep = cc.find_library('cygipc', required: false)
2606 cygipc_dep = not_found_dep
2609 if host_system == 'sunos'
2610 socket_dep = cc.find_library('socket', required: false)
2612 socket_dep = not_found_dep
2615 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2616 # unnecessary checks over and over, particularly on windows.
2618 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2619 ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2621 ['copy_file_range'],
2622 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2623 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2624 # required. Just checking for dlsym() ought to suffice.
2625 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2630 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2631 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2641 ['posix_fallocate'],
2643 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2644 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2645 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2646 ['setproctitle', {'dependencies': [util_dep]}],
2647 ['setproctitle_fast'],
2648 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2649 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2650 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2651 ['socket', {'dependencies': [socket_dep], 'define': false}],
2653 ['strerror_r', {'dependencies': [thread_dep]}],
2659 ['sync_file_range'],
2665 func_check_results = {}
2666 foreach c : func_checks
2668 kwargs = c.get(1, {})
2669 deps = kwargs.get('dependencies', [])
2671 if kwargs.get('skip', false)
2675 found = cc.has_function(func, args: test_c_args)
2682 found = cc.has_function(func, args: test_c_args,
2683 dependencies: [dep])
2691 func_check_results += {func: found}
2693 if kwargs.get('define', true)
2694 # Emulate autoconf behaviour of not-found->undef, found->1
2695 cdata.set('HAVE_' + func.underscorify().to_upper(),
2697 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2702 if cc.has_function('syslog', args: test_c_args) and \
2703 cc.check_header('syslog.h', args: test_c_args)
2704 cdata.set('HAVE_SYSLOG', 1)
2708 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2710 if sema_kind == 'unnamed_posix' and \
2711 not func_check_results.get('sem_init', false)
2715 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2716 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2718 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2719 cdata.set_quoted('DLSUFFIX', dlsuffix)
2722 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2723 cdata.set_quoted('PG_VERSION_STR',
2724 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2725 pg_version, host_machine.cpu_family(), host_system,
2726 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2731 ###############################################################
2733 ###############################################################
2735 nlsopt = get_option('nls')
2736 libintl = not_found_dep
2738 if not nlsopt.disabled()
2739 # otherwise there'd be lots of
2740 # "Gettext not found, all translation (po) targets will be ignored."
2741 # warnings if not found.
2742 msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2744 # meson 0.59 has this wrapped in dependency('intl')
2745 if (msgfmt.found() and
2746 cc.check_header('libintl.h', required: nlsopt,
2747 args: test_c_args, include_directories: postgres_inc))
2750 if cc.has_function('ngettext')
2751 libintl = declare_dependency()
2753 libintl = cc.find_library('intl',
2754 has_headers: ['libintl.h'], required: nlsopt,
2755 header_include_directories: postgres_inc,
2761 i18n = import('i18n')
2762 cdata.set('ENABLE_NLS', 1)
2768 ###############################################################
2770 ###############################################################
2772 # Set up compiler / linker arguments to be used everywhere, individual targets
2773 # can add further args directly, or indirectly via dependencies
2774 add_project_arguments(cflags, language: ['c'])
2775 add_project_arguments(cppflags, language: ['c'])
2776 add_project_arguments(cflags_warn, language: ['c'])
2777 add_project_arguments(cxxflags, language: ['cpp'])
2778 add_project_arguments(cppflags, language: ['cpp'])
2779 add_project_arguments(cxxflags_warn, language: ['cpp'])
2780 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2783 # Collect a number of lists of things while recursing through the source
2784 # tree. Later steps then can use those.
2786 # list of targets for various alias targets
2787 backend_targets = []
2790 contrib_targets = []
2791 testprep_targets = []
2795 # Define the tests to distribute them to the correct test styles later
2800 # Default options for targets
2802 # First identify rpaths
2803 bin_install_rpaths = []
2804 lib_install_rpaths = []
2805 mod_install_rpaths = []
2808 # Don't add rpaths on darwin for now - as long as only absolute references to
2809 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2810 # their final destination.
2811 if host_system != 'darwin'
2812 # Add absolute path to libdir to rpath. This ensures installed binaries /
2813 # libraries find our libraries (mainly libpq).
2814 bin_install_rpaths += dir_prefix / dir_lib
2815 lib_install_rpaths += dir_prefix / dir_lib
2816 mod_install_rpaths += dir_prefix / dir_lib
2818 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2820 # Not needed on darwin even if we use relative rpaths for our own libraries,
2821 # as the install_name of libraries in extra_lib_dirs will point to their
2823 bin_install_rpaths += postgres_lib_d
2824 lib_install_rpaths += postgres_lib_d
2825 mod_install_rpaths += postgres_lib_d
2829 # Define arguments for default targets
2831 default_target_args = {
2832 'implicit_include_directories': false,
2836 default_lib_args = default_target_args + {
2840 internal_lib_args = default_lib_args + {
2841 'build_by_default': false,
2845 default_mod_args = default_lib_args + {
2847 'install_dir': dir_lib_pkg,
2850 default_bin_args = default_target_args + {
2851 'install_dir': dir_bin,
2854 if get_option('rpath')
2855 default_lib_args += {
2856 'install_rpath': ':'.join(lib_install_rpaths),
2859 default_mod_args += {
2860 'install_rpath': ':'.join(mod_install_rpaths),
2863 default_bin_args += {
2864 'install_rpath': ':'.join(bin_install_rpaths),
2869 # Helper for exporting a limited number of symbols
2870 gen_export_kwargs = {
2871 'input': 'exports.txt',
2872 'output': '@BASENAME@.'+export_file_suffix,
2873 'command': [perl, files('src/tools/gen_export.pl'),
2874 '--format', export_file_format,
2875 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2876 'build_by_default': false,
2883 ### Helpers for custom targets used across the tree
2886 catalog_pm = files('src/backend/catalog/Catalog.pm')
2887 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2888 gen_kwlist_deps = [perfect_hash_pm]
2890 perl, '-I', '@SOURCE_ROOT@/src/tools',
2891 files('src/tools/gen_keywordlist.pl'),
2892 '--output', '@OUTDIR@', '@INPUT@']
2897 ### windows resources related stuff
2900 if host_system == 'windows'
2901 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2902 win32ver_rc = files('src/port/win32ver.rc')
2903 rcgen = find_program('src/tools/rcgen', native: true)
2906 '--srcdir', '@SOURCE_DIR@',
2907 '--builddir', meson.build_root(),
2908 '--rcout', '@OUTPUT0@',
2909 '--out', '@OUTPUT1@',
2910 '--input', '@INPUT@',
2914 if cc.get_argument_syntax() == 'msvc'
2915 rc = find_program('rc', required: true)
2916 rcgen_base_args += ['--rc', rc.path()]
2917 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2919 windres = find_program('windres', required: true)
2920 rcgen_base_args += ['--windres', windres.path()]
2921 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2924 # msbuild backend doesn't support this atm
2925 if meson.backend() == 'ninja'
2926 rcgen_base_args += ['--depfile', '@DEPFILE@']
2929 rcgen_bin_args = rcgen_base_args + [
2930 '--VFT_TYPE', 'VFT_APP',
2931 '--FILEENDING', 'exe',
2935 rcgen_lib_args = rcgen_base_args + [
2936 '--VFT_TYPE', 'VFT_DLL',
2937 '--FILEENDING', 'dll',
2940 rc_bin_gen = generator(rcgen,
2941 depfile: '@BASENAME@.d',
2942 arguments: rcgen_bin_args,
2943 output: rcgen_outputs,
2946 rc_lib_gen = generator(rcgen,
2947 depfile: '@BASENAME@.d',
2948 arguments: rcgen_lib_args,
2949 output: rcgen_outputs,
2955 # headers that the whole build tree depends on
2956 generated_headers = []
2957 # headers that the backend build depends on
2958 generated_backend_headers = []
2959 # configure_files() output, needs a way of converting to file names
2960 configure_files = []
2962 # generated files that might conflict with a partial in-tree autoconf build
2963 generated_sources = []
2964 # same, for paths that differ between autoconf / meson builds
2965 # elements are [dir, [files]]
2966 generated_sources_ac = {}
2969 # First visit src/include - all targets creating headers are defined
2970 # within. That makes it easy to add the necessary dependencies for the
2971 # subsequent build steps.
2973 subdir('src/include')
2977 # Then through src/port and src/common, as most other things depend on them
2979 frontend_port_code = declare_dependency(
2980 compile_args: ['-DFRONTEND'],
2981 include_directories: [postgres_inc],
2982 dependencies: os_deps,
2985 backend_port_code = declare_dependency(
2986 compile_args: ['-DBUILDING_DLL'],
2987 include_directories: [postgres_inc],
2988 sources: [errcodes], # errcodes.h is needed due to use of ereport
2989 dependencies: os_deps,
2994 frontend_common_code = declare_dependency(
2995 compile_args: ['-DFRONTEND'],
2996 include_directories: [postgres_inc],
2997 sources: generated_headers,
2998 dependencies: [os_deps, zlib, zstd, lz4],
3001 backend_common_code = declare_dependency(
3002 compile_args: ['-DBUILDING_DLL'],
3003 include_directories: [postgres_inc],
3004 sources: generated_headers,
3005 dependencies: [os_deps, zlib, zstd],
3008 subdir('src/common')
3010 # all shared libraries should depend on shlib_code
3011 shlib_code = declare_dependency(
3012 link_args: ldflags_sl,
3015 # all static libraries not part of the backend should depend on this
3016 frontend_stlib_code = declare_dependency(
3017 include_directories: [postgres_inc],
3018 link_with: [common_static, pgport_static],
3019 sources: generated_headers,
3020 dependencies: [os_deps, libintl],
3023 # all shared libraries not part of the backend should depend on this
3024 frontend_shlib_code = declare_dependency(
3025 include_directories: [postgres_inc],
3026 link_with: [common_shlib, pgport_shlib],
3027 sources: generated_headers,
3028 dependencies: [shlib_code, os_deps, libintl],
3031 # Dependencies both for static and shared libpq
3041 subdir('src/interfaces/libpq')
3042 # fe_utils depends on libpq
3043 subdir('src/fe_utils')
3045 # for frontend binaries
3046 frontend_code = declare_dependency(
3047 include_directories: [postgres_inc],
3048 link_with: [fe_utils, common_static, pgport_static],
3049 sources: generated_headers,
3050 dependencies: [os_deps, libintl],
3053 backend_both_deps += [
3070 backend_mod_deps = backend_both_deps + os_deps
3072 backend_code = declare_dependency(
3073 compile_args: ['-DBUILDING_DLL'],
3074 include_directories: [postgres_inc],
3075 link_args: ldflags_be,
3077 sources: generated_headers + generated_backend_headers,
3078 dependencies: os_deps + backend_both_deps + backend_deps,
3081 # install these files only during test, not main install
3082 test_install_data = []
3083 test_install_libs = []
3085 # src/backend/meson.build defines backend_mod_code used for extension
3089 # Then through the main sources. That way contrib can have dependencies on
3090 # main sources. Note that this explicitly doesn't enter src/test, right now a
3091 # few regression tests depend on contrib files.
3098 subdir('src/interfaces/libpq/test')
3099 subdir('src/interfaces/ecpg/test')
3101 subdir('doc/src/sgml')
3103 generated_sources_ac += {'': ['GNUmakefile']}
3105 # After processing src/test, add test_install_libs to the testprep_targets
3107 testprep_targets += test_install_libs
3110 # If there are any files in the source directory that we also generate in the
3111 # build directory, they might get preferred over the newly generated files,
3112 # e.g. because of a #include "file", which always will search in the current
3114 message('checking for file conflicts between source and build directory')
3115 conflicting_files = []
3116 potentially_conflicting_files_t = []
3117 potentially_conflicting_files_t += generated_headers
3118 potentially_conflicting_files_t += generated_backend_headers
3119 potentially_conflicting_files_t += generated_backend_sources
3120 potentially_conflicting_files_t += generated_sources
3122 potentially_conflicting_files = []
3124 # convert all sources of potentially conflicting files into uniform shape
3125 foreach t : potentially_conflicting_files_t
3126 potentially_conflicting_files += t.full_path()
3128 foreach t1 : configure_files
3129 if meson.version().version_compare('>=0.59')
3130 t = fs.parent(t1) / fs.name(t1)
3132 t = '@0@'.format(t1)
3134 potentially_conflicting_files += meson.current_build_dir() / t
3136 foreach sub, fnames : generated_sources_ac
3137 sub = meson.build_root() / sub
3138 foreach fname : fnames
3139 potentially_conflicting_files += sub / fname
3143 # find and report conflicting files
3144 foreach build_path : potentially_conflicting_files
3145 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3146 # str.replace is in 0.56
3147 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3148 if fs.exists(src_path) or fs.is_symlink(src_path)
3149 conflicting_files += src_path
3152 # XXX: Perhaps we should generate a file that would clean these up? The list
3154 if conflicting_files.length() > 0
3155 errmsg_cleanup = '''
3156 Conflicting files in source directory:
3159 The conflicting files need to be removed, either by removing the files listed
3160 above, or by running configure and then make maintainer-clean.
3162 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3163 error(errmsg_nonclean_base.format(errmsg_cleanup))
3168 ###############################################################
3170 ###############################################################
3173 # We want to define additional install targets beyond what meson provides. For
3174 # that we need to define targets depending on nearly everything. We collected
3175 # the results of i18n.gettext() invocations into nls_targets, that also
3176 # includes maintainer targets though. Collect the ones we want as a dependency.
3178 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3179 # generation happens during install, so that's not a real issue.
3181 if libintl.found() and meson.version().version_compare('>=0.60')
3182 # use range() to avoid the flattening of the list that foreach() would do
3183 foreach off : range(0, nls_targets.length())
3184 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3185 # -pot target 3) maintainer -pot target
3186 nls_mo_targets += nls_targets[off][0]
3188 alias_target('nls', nls_mo_targets)
3203 # Meson's default install target is quite verbose. Provide one that is quiet.
3204 install_quiet = custom_target('install-quiet',
3205 output: 'install-quiet',
3206 build_always_stale: true,
3207 build_by_default: false,
3208 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3212 # Target to install files used for tests, which aren't installed by default
3213 install_test_files_args = [
3215 '--prefix', dir_prefix,
3216 '--install', contrib_data_dir, test_install_data,
3217 '--install', dir_lib_pkg, test_install_libs,
3219 run_target('install-test-files',
3220 command: [python] + install_test_files_args,
3221 depends: testprep_targets,
3226 ###############################################################
3228 ###############################################################
3230 # DESTDIR for the installation we'll run tests in
3231 test_install_destdir = meson.build_root() / 'tmp_install/'
3233 # DESTDIR + prefix appropriately munged
3234 if build_system != 'windows'
3235 # On unixoid systems this is trivial, we just prepend the destdir
3236 assert(dir_prefix.startswith('/')) # enforced by meson
3237 temp_install_bindir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_bin)
3238 temp_install_libdir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_lib)
3240 # drives, drive-relative paths, etc make this complicated on windows, call
3241 # into a copy of meson's logic for it
3244 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3245 test_install_destdir]
3246 temp_install_bindir = run_command(command, dir_prefix / dir_bin, check: true).stdout().strip()
3247 temp_install_libdir = run_command(command, dir_prefix / dir_lib, check: true).stdout().strip()
3250 meson_install_args = meson_args + ['install'] + {
3251 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3255 # setup tests should be run first,
3256 # so define priority for these
3257 setup_tests_priority = 100
3259 meson_bin, args: meson_install_args ,
3260 env: {'DESTDIR':test_install_destdir},
3261 priority: setup_tests_priority,
3266 test('install_test_files',
3268 args: install_test_files_args + ['--destdir', test_install_destdir],
3269 priority: setup_tests_priority,
3273 test_result_dir = meson.build_root() / 'testrun'
3276 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3277 # inevitable conflicts from running tests in parallel, hackishly assign
3278 # different ports for different tests.
3282 test_env = environment()
3284 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3285 test_env.set('PG_REGRESS', pg_regress.full_path())
3286 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3287 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3289 # Add the temporary installation to the library search path on platforms where
3290 # that works (everything but windows, basically). On windows everything
3291 # library-like gets installed into bindir, solving that issue.
3292 if library_path_var != ''
3293 test_env.prepend(library_path_var, temp_install_libdir)
3297 # Create (and remove old) initdb template directory. Tests use that, where
3298 # possible, to make it cheaper to run tests.
3300 # Use python to remove the old cached initdb, as we cannot rely on a working
3301 # 'rm' binary on windows.
3302 test('initdb_cache',
3310 shutil.rmtree(sys.argv[1], ignore_errors=True)
3311 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3312 sys.exit(sp.returncode)
3314 test_initdb_template,
3315 temp_install_bindir / 'initdb',
3316 '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3319 priority: setup_tests_priority - 1,
3327 ###############################################################
3329 ###############################################################
3331 # When using a meson version understanding exclude_suites, define a
3332 # 'tmp_install' test setup (the default) that excludes tests running against a
3333 # pre-existing install and a 'running' setup that conflicts with creation of
3334 # the temporary installation and tap tests (which don't support running
3335 # against a running server).
3339 if meson.version().version_compare('>=0.57')
3342 runningcheck = false
3345 testwrap = files('src/tools/testwrap')
3347 foreach test_dir : tests
3350 '--basedir', meson.build_root(),
3351 '--srcdir', test_dir['sd'],
3352 # Some test suites are not run by default but can be run if selected by the
3353 # user via variable PG_TEST_EXTRA. Pass configuration time value of
3354 # PG_TEST_EXTRA as an argument to testwrap so that it can be overridden by
3355 # run time value, if any.
3356 '--pg-test-extra', get_option('PG_TEST_EXTRA'),
3359 foreach kind, v : test_dir
3360 if kind in ['sd', 'bd', 'name']
3366 if kind in ['regress', 'isolation', 'ecpg']
3367 if kind == 'regress'
3369 fallback_dbname = 'regression_@0@'
3370 elif kind == 'isolation'
3371 runner = pg_isolation_regress
3372 fallback_dbname = 'isolation_regression_@0@'
3374 runner = pg_regress_ecpg
3375 fallback_dbname = 'ecpg_regression_@0@'
3378 test_group = test_dir['name']
3379 test_group_running = test_dir['name'] + '-running'
3381 test_output = test_result_dir / test_group / kind
3382 test_output_running = test_result_dir / test_group_running/ kind
3384 # Unless specified by the test, choose a non-conflicting database name,
3385 # to avoid conflicts when running against existing server.
3386 dbname = t.get('dbname',
3387 fallback_dbname.format(test_dir['name']))
3389 test_command_base = [
3391 '--inputdir', t.get('inputdir', test_dir['sd']),
3392 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3394 '--dlpath', test_dir['bd'],
3395 '--max-concurrent-tests=20',
3397 ] + t.get('regress_args', [])
3400 if t.has_key('schedule')
3401 test_selection += ['--schedule', t['schedule'],]
3404 if kind == 'isolation'
3405 test_selection += t.get('specs', [])
3407 test_selection += t.get('sql', [])
3411 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3417 'depends': test_deps + t.get('deps', []),
3419 } + t.get('test_kwargs', {})
3421 test(test_group / kind,
3425 '--testgroup', test_group,
3429 '--outputdir', test_output,
3430 '--temp-instance', test_output / 'tmp_check',
3431 '--port', testport.to_string(),
3435 kwargs: test_kwargs,
3437 install_suites += test_group
3439 # some tests can't support running against running DB
3440 if runningcheck and t.get('runningcheck', true)
3441 test(test_group_running / kind,
3445 '--testgroup', test_group_running,
3449 '--outputdir', test_output_running,
3452 is_parallel: t.get('runningcheck-parallel', true),
3453 suite: test_group_running,
3454 kwargs: test_kwargs,
3456 running_suites += test_group_running
3461 testwrap_tap = testwrap_base
3462 if not tap_tests_enabled
3463 testwrap_tap += ['--skip', 'TAP tests not enabled']
3468 '-I', meson.source_root() / 'src/test/perl',
3469 '-I', test_dir['sd'],
3472 # Add temporary install, the build directory for non-installed binaries and
3473 # also test/ for non-installed test binaries built separately.
3475 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3477 foreach name, value : t.get('env', {})
3478 env.set(name, value)
3481 test_group = test_dir['name']
3484 'suite': test_group,
3486 'depends': test_deps + t.get('deps', []),
3488 } + t.get('test_kwargs', {})
3490 foreach onetap : t['tests']
3491 # Make tap test names prettier, remove t/ and .pl
3493 if onetap_p.startswith('t/')
3494 onetap_p = onetap.split('t/')[1]
3496 if onetap_p.endswith('.pl')
3497 onetap_p = fs.stem(onetap_p)
3500 test(test_dir['name'] / onetap_p,
3502 kwargs: test_kwargs,
3503 args: testwrap_tap + [
3504 '--testgroup', test_dir['name'],
3505 '--testname', onetap_p,
3507 test_dir['sd'] / onetap,
3511 install_suites += test_group
3513 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3516 endforeach # kinds of tests
3518 endforeach # directories with tests
3520 # repeat condition so meson realizes version dependency
3521 if meson.version().version_compare('>=0.57')
3522 add_test_setup('tmp_install',
3524 exclude_suites: running_suites)
3525 add_test_setup('running',
3526 exclude_suites: ['setup'] + install_suites)
3531 ###############################################################
3533 ###############################################################
3535 alias_target('backend', backend_targets)
3536 alias_target('bin', bin_targets + [libpq_st])
3537 alias_target('pl', pl_targets)
3538 alias_target('contrib', contrib_targets)
3539 alias_target('testprep', testprep_targets)
3541 alias_target('world', all_built, docs)
3542 alias_target('install-world', install_quiet, installdocs)
3546 perl, '-ne', 'next if /^#/; print',
3547 files('doc/src/sgml/targets-meson.txt'),
3553 ###############################################################
3554 # Distribution archive
3555 ###############################################################
3557 # Meson has its own distribution building command (meson dist), but we
3558 # are not using that at this point. The main problem is that, the way
3559 # they have implemented it, it is not deterministic. Also, we want it
3560 # to be equivalent to the "make" version for the time being. But the
3561 # target name "dist" in meson is reserved for that reason, so we call
3562 # the custom target "pgdist".
3564 git = find_program('git', required: false, native: true, disabler: true)
3565 bzip2 = find_program('bzip2', required: false, native: true)
3567 distdir = meson.project_name() + '-' + meson.project_version()
3569 pg_git_revision = get_option('PG_GIT_REVISION')
3571 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3572 # in case the environment has a different setting. Without this, a
3573 # tarball created on Windows might be different than on, and unusable
3574 # on, Unix machines.
3576 tar_gz = custom_target('tar.gz',
3577 build_always_stale: true,
3578 command: [git, '-C', '@SOURCE_ROOT@',
3579 '-c', 'core.autocrlf=false',
3581 '--format', 'tar.gz',
3583 '--prefix', distdir + '/',
3584 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3586 output: distdir + '.tar.gz',
3590 tar_bz2 = custom_target('tar.bz2',
3591 build_always_stale: true,
3592 command: [git, '-C', '@SOURCE_ROOT@',
3593 '-c', 'core.autocrlf=false',
3594 '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3596 '--format', 'tar.bz2',
3597 '--prefix', distdir + '/',
3598 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3600 output: distdir + '.tar.bz2',
3603 tar_bz2 = custom_target('tar.bz2',
3604 command: [perl, '-e', 'exit 1'],
3605 output: distdir + '.tar.bz2',
3609 alias_target('pgdist', [tar_gz, tar_bz2])
3611 # Make the standard "dist" command fail, to prevent accidental use.
3612 # But not if we are in a subproject, in case the parent project wants to
3613 # create a dist using the standard Meson command.
3614 if not meson.is_subproject()
3615 # We can only pass the identifier perl here when we depend on >= 0.55
3616 if meson.version().version_compare('>=0.55')
3617 meson.add_dist_script(perl, '-e', 'exit 1')
3623 ###############################################################
3624 # The End, The End, My Friend
3625 ###############################################################
3627 if meson.version().version_compare('>=0.57')
3631 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3632 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3633 'segment size': get_option('segsize_blocks') != 0 ?
3634 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3635 '@0@ GB'.format(get_option('segsize')),
3637 section: 'Data layout',
3642 'host system': '@0@ @1@'.format(host_system, host_cpu),
3643 'build system': '@0@ @1@'.format(build_machine.system(),
3644 build_machine.cpu_family()),
3651 'linker': '@0@'.format(cc.get_linker_id()),
3652 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3654 section: 'Compiler',
3659 'CPP FLAGS': ' '.join(cppflags),
3660 'C FLAGS, functional': ' '.join(cflags),
3661 'C FLAGS, warnings': ' '.join(cflags_warn),
3662 'C FLAGS, modules': ' '.join(cflags_mod),
3663 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3664 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3666 section: 'Compiler Flags',
3672 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3674 section: 'Compiler',
3679 'C++ FLAGS, functional': ' '.join(cxxflags),
3680 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3681 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3683 section: 'Compiler Flags',
3689 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3691 'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3693 section: 'Programs',
3699 'bsd_auth': bsd_auth,
3701 'docs_pdf': docs_pdf_dep,
3713 'plpython': python3_dep,
3715 'readline': readline,
3722 section: 'External libraries',