1 # Copyright (c) 2022-2024, 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 cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
266 elif host_system == 'windows'
270 library_path_var = ''
271 if cc.get_id() != 'msvc'
272 # define before including <time.h> for getting localtime_r() etc. on MinGW
273 cppflags += '-D_POSIX_C_SOURCE'
276 export_file_format = 'win'
277 export_file_suffix = 'def'
278 if cc.get_id() == 'msvc'
279 export_fmt = '/DEF:@0@'
280 mod_link_with_name = '@0@.lib'
283 mod_link_with_name = 'lib@0@.a'
285 mod_link_args_fmt = ['@0@']
286 mod_link_with_dir = 'libdir'
291 cdata.set('WIN32_STACK_RLIMIT', 4194304)
292 if cc.get_id() == 'msvc'
293 ldflags += '/INCREMENTAL:NO'
294 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
295 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
297 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
298 # Need to allow multiple definitions, we e.g. want to override getopt.
299 ldflags += '-Wl,--allow-multiple-definition'
300 # Ensure we get MSVC-like linking behavior.
301 ldflags += '-Wl,--disable-auto-import'
304 os_deps += cc.find_library('ws2_32', required: true)
305 secur32_dep = cc.find_library('secur32', required: true)
306 backend_deps += secur32_dep
307 libpq_deps += secur32_dep
309 postgres_inc_d += 'src/include/port/win32'
310 if cc.get_id() == 'msvc'
311 postgres_inc_d += 'src/include/port/win32_msvc'
314 windows = import('windows')
317 # XXX: Should we add an option to override the host_system as an escape
319 error('unknown host system: @0@'.format(host_system))
324 ###############################################################
326 ###############################################################
329 perl = find_program(get_option('PERL'), required: true, native: true)
330 python = find_program(get_option('PYTHON'), required: true, native: true)
331 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
332 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
333 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
334 prove = find_program(get_option('PROVE'), native: true, required: false)
335 tar = find_program(get_option('TAR'), native: true, required: false)
336 gzip = find_program(get_option('GZIP'), native: true, required: false)
337 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
338 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
339 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
340 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
341 missing = find_program('config/missing', native: true)
342 cp = find_program('cp', required: false, native: true)
343 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
344 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
348 bison_version_c = run_command(bison, '--version', check: true)
349 # bison version string helpfully is something like
350 # >>bison (GNU bison) 3.8.1<<
351 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
352 if bison_version.version_compare('>=3.0')
353 bison_flags += ['-Wno-deprecated']
356 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
358 'output': ['@BASENAME@.c', '@BASENAME@.h'],
359 'command': bison_cmd,
364 flex_version_c = run_command(flex, '--version', check: true)
365 flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
367 flex_wrapper = files('src/tools/pgflex')
368 flex_cmd = [python, flex_wrapper,
369 '--builddir', '@BUILD_ROOT@',
370 '--srcdir', '@SOURCE_ROOT@',
371 '--privatedir', '@PRIVATE_DIR@',
372 '--flex', flex, '--perl', perl,
373 '-i', '@INPUT@', '-o', '@OUTPUT0@',
376 wget = find_program('wget', required: false, native: true)
377 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
379 install_files = files('src/tools/install_files')
383 ###############################################################
384 # Path to meson (for tests etc)
385 ###############################################################
387 # NB: this should really be part of meson, see
388 # https://github.com/mesonbuild/meson/issues/8511
389 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
391 if meson_binpath_r.stdout() == ''
392 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
393 meson_binpath_r.returncode(),
394 meson_binpath_r.stdout(),
395 meson_binpath_r.stderr()))
398 meson_binpath_s = meson_binpath_r.stdout().split('\n')
399 meson_binpath_len = meson_binpath_s.length()
401 if meson_binpath_len < 1
402 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
409 foreach e : meson_binpath_s
420 if meson_impl not in ['muon', 'meson']
421 error('unknown meson implementation "@0@"'.format(meson_impl))
424 meson_bin = find_program(meson_binpath, native: true)
428 ###############################################################
430 ###############################################################
432 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
433 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
435 blocksize = get_option('blocksize').to_int() * 1024
437 if get_option('segsize_blocks') != 0
438 if get_option('segsize') != 1
439 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
442 segsize = get_option('segsize_blocks')
444 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
447 cdata.set('BLCKSZ', blocksize, description:
448 '''Size of a disk block --- this also limits the size of a tuple. You can set
449 it bigger if you need bigger tuples (although TOAST should reduce the need
450 to have large tuples, since fields can be spread across multiple tuples).
451 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
452 currently 2^15 (32768). This is determined by the 15-bit widths of the
453 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
454 Changing BLCKSZ requires an initdb.''')
456 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
457 cdata.set('RELSEG_SIZE', segsize)
458 cdata.set('DEF_PGPORT', get_option('pgport'))
459 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
460 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
461 if get_option('system_tzdata') != ''
462 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
467 ###############################################################
469 ###############################################################
471 # These are set by the equivalent --xxxdir configure options. We
472 # append "postgresql" to some of them, if the string does not already
473 # contain "pgsql" or "postgres", in order to avoid directory clutter.
477 dir_prefix = get_option('prefix')
479 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
481 dir_bin = get_option('bindir')
483 dir_data = get_option('datadir')
484 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
485 dir_data = dir_data / pkg
488 dir_sysconf = get_option('sysconfdir')
489 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
490 dir_sysconf = dir_sysconf / pkg
493 dir_lib = get_option('libdir')
495 dir_lib_pkg = dir_lib
496 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
497 dir_lib_pkg = dir_lib_pkg / pkg
500 dir_pgxs = dir_lib_pkg / 'pgxs'
502 dir_include = get_option('includedir')
504 dir_include_pkg = dir_include
505 dir_include_pkg_rel = ''
506 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
507 dir_include_pkg = dir_include_pkg / pkg
508 dir_include_pkg_rel = pkg
511 dir_man = get_option('mandir')
513 # FIXME: These used to be separately configurable - worth adding?
514 dir_doc = get_option('datadir') / 'doc'
515 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
516 dir_doc = dir_doc / pkg
518 dir_doc_html = dir_doc / 'html'
520 dir_locale = get_option('localedir')
524 dir_bitcode = dir_lib_pkg / 'bitcode'
525 dir_include_internal = dir_include_pkg / 'internal'
526 dir_include_server = dir_include_pkg / 'server'
527 dir_include_extension = dir_include_server / 'extension'
528 dir_data_extension = dir_data / 'extension'
529 dir_doc_extension = dir_doc / 'extension'
533 ###############################################################
534 # Search paths, preparation for compiler tests
536 # NB: Arguments added later are not automatically used for subsequent
537 # configuration-time checks (so they are more isolated). If they should be
538 # used, they need to be added to test_c_args as well.
539 ###############################################################
541 postgres_inc = [include_directories(postgres_inc_d)]
542 test_lib_d = postgres_lib_d
543 test_c_args = cppflags + cflags
547 ###############################################################
549 ###############################################################
551 bsd_authopt = get_option('bsd_auth')
552 bsd_auth = not_found_dep
553 if cc.check_header('bsd_auth.h', required: bsd_authopt,
554 args: test_c_args, include_directories: postgres_inc)
555 cdata.set('USE_BSD_AUTH', 1)
556 bsd_auth = declare_dependency()
561 ###############################################################
564 # For now don't search for DNSServiceRegister in a library - only Apple's
565 # Bonjour implementation, which is always linked, works.
566 ###############################################################
568 bonjouropt = get_option('bonjour')
569 bonjour = not_found_dep
570 if cc.check_header('dns_sd.h', required: bonjouropt,
571 args: test_c_args, include_directories: postgres_inc) and \
572 cc.has_function('DNSServiceRegister',
573 args: test_c_args, include_directories: postgres_inc)
574 cdata.set('USE_BONJOUR', 1)
575 bonjour = declare_dependency()
580 ###############################################################
581 # Option: docs in HTML and man page format
582 ###############################################################
584 docs_opt = get_option('docs')
585 docs_dep = not_found_dep
586 if not docs_opt.disabled()
587 if xmllint_bin.found() and xsltproc_bin.found()
588 docs_dep = declare_dependency()
589 elif docs_opt.enabled()
590 error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
596 ###############################################################
597 # Option: docs in PDF format
598 ###############################################################
600 docs_pdf_opt = get_option('docs_pdf')
601 docs_pdf_dep = not_found_dep
602 if not docs_pdf_opt.disabled()
603 fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
604 if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
605 docs_pdf_dep = declare_dependency()
606 elif docs_pdf_opt.enabled()
607 error('missing required tools for docs in PDF format')
613 ###############################################################
615 ###############################################################
617 gssapiopt = get_option('gssapi')
620 if not gssapiopt.disabled()
621 gssapi = dependency('krb5-gssapi', required: false)
622 have_gssapi = gssapi.found()
625 gssapi_deps = [gssapi]
627 # Hardcoded lookup for gssapi. This is necessary as gssapi on windows does
628 # not install neither pkg-config nor cmake dependency information.
629 if host_system == 'windows'
630 is_64 = cc.sizeof('void *', args: test_c_args) == 8
632 gssapi_search_libs = ['gssapi64', 'krb5_64', 'comerr64']
634 gssapi_search_libs = ['gssapi32', 'krb5_32', 'comerr32']
637 gssapi_search_libs = ['gssapi_krb5']
641 foreach libname : gssapi_search_libs
642 lib = cc.find_library(libname, dirs: test_lib_d, required: false)
650 # Meson before 0.57.0 did not support using check_header() etc with
651 # declare_dependency(). Thus the tests below use the library looked up
652 # above. Once we require a newer meson version, we can simplify.
653 gssapi = declare_dependency(dependencies: gssapi_deps)
658 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi_deps, required: false,
659 args: test_c_args, include_directories: postgres_inc)
660 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
661 elif cc.check_header('gssapi.h', dependencies: gssapi_deps, required: gssapiopt,
662 args: test_c_args, include_directories: postgres_inc)
663 cdata.set('HAVE_GSSAPI_H', 1)
669 elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi_deps, required: false,
670 args: test_c_args, include_directories: postgres_inc)
671 cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
672 elif cc.check_header('gssapi_ext.h', dependencies: gssapi_deps, required: gssapiopt,
673 args: test_c_args, include_directories: postgres_inc)
674 cdata.set('HAVE_GSSAPI_EXT_H', 1)
680 elif cc.has_function('gss_store_cred_into', dependencies: gssapi_deps,
681 args: test_c_args, include_directories: postgres_inc)
682 cdata.set('ENABLE_GSS', 1)
684 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
685 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
686 elif gssapiopt.enabled()
687 error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
692 if not have_gssapi and gssapiopt.enabled()
693 error('dependency lookup for gssapi failed')
698 gssapi = not_found_dep
703 ###############################################################
705 ###############################################################
707 ldapopt = get_option('ldap')
708 if ldapopt.disabled()
710 ldap_r = not_found_dep
711 elif host_system == 'windows'
712 ldap = cc.find_library('wldap32', required: ldapopt)
715 # macos framework dependency is buggy for ldap (one can argue whether it's
716 # Apple's or meson's fault), leading to an endless recursion with ldap.h
717 # including itself. See https://github.com/mesonbuild/meson/issues/10002
718 # Luckily we only need pkg-config support, so the workaround isn't
720 ldap = dependency('ldap', method: 'pkg-config', required: false)
723 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
726 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
727 has_headers: 'ldap.h', header_include_directories: postgres_inc)
729 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
730 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
731 # library from a separate OpenLDAP installation). The most reliable
732 # way to check that is to check for a function introduced in 2.5.
734 # don't have ldap, we shouldn't check for ldap_r
735 elif cc.has_function('ldap_verify_credentials',
736 dependencies: ldap, args: test_c_args)
737 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
740 # Use ldap_r for FE if available, else assume ldap is thread-safe.
741 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
742 has_headers: 'ldap.h', header_include_directories: postgres_inc)
743 if not ldap_r.found()
746 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
747 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
750 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
751 # process. Check for OpenLDAP versions known not to tolerate doing so;
752 # assume non-OpenLDAP implementations are safe. The dblink test suite
753 # exercises the hazardous interaction directly.
754 compat_test_code = '''
756 #if !defined(LDAP_VENDOR_VERSION) || \
757 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
758 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
762 if not cc.compiles(compat_test_code,
763 name: 'LDAP implementation compatible',
764 dependencies: ldap, args: test_c_args)
766 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
767 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
768 *** also uses LDAP will crash on exit.''')
773 if ldap.found() and cc.has_function('ldap_initialize',
774 dependencies: ldap, args: test_c_args)
775 cdata.set('HAVE_LDAP_INITIALIZE', 1)
780 assert(ldap_r.found())
781 cdata.set('USE_LDAP', 1)
783 assert(not ldap_r.found())
788 ###############################################################
790 ###############################################################
792 llvmopt = get_option('llvm')
794 if add_languages('cpp', required: llvmopt, native: false)
795 llvm = dependency('llvm', version: '>=10', method: 'config-tool', required: llvmopt)
799 cdata.set('USE_LLVM', 1)
801 cpp = meson.get_compiler('cpp')
803 llvm_binpath = llvm.get_variable(configtool: 'bindir')
805 ccache = find_program('ccache', native: true, required: false)
807 # Some distros put LLVM and clang in different paths, so fallback to
808 # find via PATH, too.
809 clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
812 message('llvm requires a C++ compiler')
817 ###############################################################
819 ###############################################################
821 icuopt = get_option('icu')
822 if not icuopt.disabled()
823 icu = dependency('icu-uc', required: false)
825 icu_i18n = dependency('icu-i18n', required: true)
828 # Unfortunately the dependency is named differently with cmake
829 if not icu.found() # combine with above once meson 0.60.0 is required
830 icu = dependency('ICU', required: icuopt,
831 components: ['uc'], modules: ['ICU::uc'], method: 'cmake')
833 icu_i18n = dependency('ICU', required: true,
834 components: ['i18n'], modules: ['ICU::i18n'])
839 cdata.set('USE_ICU', 1)
841 icu_i18n = not_found_dep
846 icu_i18n = not_found_dep
851 ###############################################################
853 ###############################################################
855 libxmlopt = get_option('libxml')
856 if not libxmlopt.disabled()
857 libxml = dependency('libxml-2.0', required: false, version: '>= 2.6.23')
858 # Unfortunately the dependency is named differently with cmake
859 if not libxml.found() # combine with above once meson 0.60.0 is required
860 libxml = dependency('LibXml2', required: libxmlopt, version: '>= 2.6.23',
865 cdata.set('USE_LIBXML', 1)
868 libxml = not_found_dep
873 ###############################################################
875 ###############################################################
877 libxsltopt = get_option('libxslt')
878 if not libxsltopt.disabled()
879 libxslt = dependency('libxslt', required: false)
880 # Unfortunately the dependency is named differently with cmake
881 if not libxslt.found() # combine with above once meson 0.60.0 is required
882 libxslt = dependency('LibXslt', required: libxsltopt, method: 'cmake')
886 cdata.set('USE_LIBXSLT', 1)
889 libxslt = not_found_dep
894 ###############################################################
896 ###############################################################
898 lz4opt = get_option('lz4')
899 if not lz4opt.disabled()
900 lz4 = dependency('liblz4', required: false)
901 # Unfortunately the dependency is named differently with cmake
902 if not lz4.found() # combine with above once meson 0.60.0 is required
903 lz4 = dependency('lz4', required: lz4opt,
904 method: 'cmake', modules: ['LZ4::lz4_shared'],
909 cdata.set('USE_LZ4', 1)
910 cdata.set('HAVE_LIBLZ4', 1)
919 ###############################################################
920 # Library: Tcl (for pltcl)
922 # NB: tclConfig.sh is used in autoconf build for getting
923 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
924 # variables. For now we have not seen a need to copy
925 # that behaviour to the meson build.
926 ###############################################################
928 tclopt = get_option('pltcl')
929 tcl_version = get_option('tcl_version')
930 tcl_dep = not_found_dep
931 if not tclopt.disabled()
934 tcl_dep = dependency(tcl_version, required: false)
936 if not tcl_dep.found()
937 tcl_dep = cc.find_library(tcl_version,
942 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
943 tcl_dep = not_found_dep
949 ###############################################################
951 ###############################################################
953 pamopt = get_option('pam')
954 if not pamopt.disabled()
955 pam = dependency('pam', required: false)
958 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
962 pam_header_found = false
964 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
965 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
966 args: test_c_args, include_directories: postgres_inc)
967 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
968 pam_header_found = true
969 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
970 args: test_c_args, include_directories: postgres_inc)
971 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
972 pam_header_found = true
976 cdata.set('USE_PAM', 1)
987 ###############################################################
988 # Library: Perl (for plperl)
989 ###############################################################
991 perlopt = get_option('plperl')
992 perl_dep = not_found_dep
993 if not perlopt.disabled()
996 # First verify that perl has the necessary dependencies installed
997 perl_mods = run_command(
999 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
1002 if perl_mods.returncode() != 0
1003 perl_may_work = false
1004 perl_msg = 'perl installation does not have the required modules'
1007 # Then inquire perl about its configuration
1009 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
1010 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
1011 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
1012 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
1013 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
1015 perl_inc_dir = '@0@/CORE'.format(archlibexp)
1017 if perlversion.version_compare('< 5.14')
1018 perl_may_work = false
1019 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
1020 elif useshrplib != 'true'
1021 perl_may_work = false
1022 perl_msg = 'need a shared perl'
1027 # On most platforms, archlibexp is also where the Perl include files live ...
1028 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
1029 # ... but on newer macOS versions, we must use -iwithsysroot to look
1031 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
1032 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
1033 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
1036 # check compiler finds header
1037 if not cc.has_header('perl.h', required: false,
1038 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
1039 perl_may_work = false
1040 perl_msg = 'missing perl.h'
1045 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
1047 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
1048 foreach flag : perl_ccflags_r.split(' ')
1049 if flag.startswith('-D') and \
1050 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
1051 perl_ccflags += flag
1055 if host_system == 'windows'
1056 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
1058 if cc.get_id() == 'msvc'
1059 # prevent binary mismatch between MSVC built plperl and Strawberry or
1060 # msys ucrt perl libraries
1061 perl_v = run_command(perl, '-V').stdout()
1062 if not perl_v.contains('USE_THREAD_SAFE_LOCALE')
1063 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
1068 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
1069 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
1071 # We are after Embed's ldopts, but without the subset mentioned in
1072 # Config's ccdlflags and ldflags. (Those are the choices of those who
1073 # built the Perl installation, which are not necessarily appropriate
1074 # for building PostgreSQL.)
1075 perl_ldopts = run_command(perl, '-e', '''
1076 use ExtUtils::Embed;
1077 use Text::ParseWords;
1078 # tell perl to suppress including these in ldopts
1079 *ExtUtils::Embed::_ldflags =*ExtUtils::Embed::_ccdlflags = sub { return ""; };
1080 # adding an argument to ldopts makes it return a value instead of printing
1081 # print one of these per line so splitting will preserve spaces in file names.
1082 # shellwords eats backslashes, so we need to escape them.
1083 (my $opts = ldopts(undef)) =~ s!\\!\\\\!g;
1084 print "$_\n" foreach shellwords($opts);
1086 check: true).stdout().strip().split('\n')
1088 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1090 perl_dep_int = declare_dependency(
1091 compile_args: perl_ccflags,
1092 link_args: perl_ldopts,
1093 version: perlversion,
1096 # While we're at it, check that we can link to libperl.
1097 # On most platforms, if perl.h is there then libperl.so will be too, but
1098 # at this writing Debian packages them separately.
1099 perl_link_test = '''
1102 #define __inline__ inline
1110 if not cc.links(perl_link_test, name: 'libperl',
1111 args: test_c_args + perl_ccflags + perl_ldopts,
1112 include_directories: postgres_inc)
1113 perl_may_work = false
1114 perl_msg = 'missing libperl'
1117 endif # perl_may_work
1120 perl_dep = perl_dep_int
1122 if perlopt.enabled()
1123 error('dependency plperl failed: @0@'.format(perl_msg))
1125 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1132 ###############################################################
1133 # Library: Python (for plpython)
1134 ###############################################################
1136 pyopt = get_option('plpython')
1137 python3_dep = not_found_dep
1138 if not pyopt.disabled()
1139 pm = import('python')
1140 python3_inst = pm.find_installation(python.path(), required: pyopt)
1141 if python3_inst.found()
1142 python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1143 # Remove this check after we depend on Meson >= 1.1.0
1144 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1145 python3_dep = not_found_dep
1152 ###############################################################
1154 ###############################################################
1156 if not get_option('readline').disabled()
1157 libedit_preferred = get_option('libedit_preferred')
1158 # Set the order of readline dependencies.
1159 # cc.find_library breaks and throws on the first dependency which
1160 # is marked as required=true and can't be found. Thus, we only mark
1161 # the last dependency to look up as required, to not throw too early.
1162 check_readline_deps = [
1164 'name': libedit_preferred ? 'libedit' : 'readline',
1168 'name': libedit_preferred ? 'readline' : 'libedit',
1169 'required': get_option('readline')
1173 foreach readline_dep : check_readline_deps
1174 readline = dependency(readline_dep['name'], required: false)
1175 if not readline.found()
1176 readline = cc.find_library(readline_dep['name'],
1177 required: readline_dep['required'],
1186 cdata.set('HAVE_LIBREADLINE', 1)
1189 'header_prefix': 'editline/',
1190 'flag_prefix': 'EDITLINE_',
1193 'header_prefix': 'readline/',
1194 'flag_prefix': 'READLINE_',
1197 'header_prefix': '',
1201 # Set the order of prefixes
1202 prefixes = libedit_preferred ? \
1203 [editline_prefix, default_prefix, readline_prefix] : \
1204 [readline_prefix, default_prefix, editline_prefix]
1206 at_least_one_header_found = false
1207 foreach header : ['history', 'readline']
1209 foreach prefix : prefixes
1210 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1211 # Check history.h and readline.h
1212 if not is_found and cc.has_header(header_file,
1213 args: test_c_args, include_directories: postgres_inc,
1214 dependencies: [readline], required: false)
1215 if header == 'readline'
1216 readline_h = header_file
1218 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1220 at_least_one_header_found = true
1225 if not at_least_one_header_found
1226 error('''readline header not found
1227 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1228 failure. It is possible the compiler isn't looking in the proper directory.
1229 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1234 'history_truncate_file',
1235 'rl_completion_matches',
1236 'rl_filename_completion_function',
1237 'rl_reset_screen_size',
1241 foreach func : check_funcs
1242 found = cc.has_function(func, dependencies: [readline],
1243 args: test_c_args, include_directories: postgres_inc)
1244 cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1248 'rl_completion_suppress_quote',
1249 'rl_filename_quote_characters',
1250 'rl_filename_quoting_function',
1253 foreach var : check_vars
1254 cdata.set('HAVE_' + var.to_upper(),
1255 cc.has_header_symbol(readline_h, var,
1256 args: test_c_args, include_directories: postgres_inc,
1257 prefix: '#include <stdio.h>',
1258 dependencies: [readline]) ? 1 : false)
1261 # If found via cc.find_library() ensure headers are found when using the
1262 # dependency. On meson < 0.57 one cannot do compiler checks using the
1263 # dependency returned by declare_dependency(), so we can't do this above.
1264 if readline.type_name() == 'library'
1265 readline = declare_dependency(dependencies: readline,
1266 include_directories: postgres_inc)
1269 # On windows with mingw readline requires auto-import to successfully
1270 # link, as the headers don't use declspec(dllimport)
1271 if host_system == 'windows' and cc.get_id() != 'msvc'
1272 readline = declare_dependency(dependencies: readline,
1273 link_args: '-Wl,--enable-auto-import')
1277 # XXX: Figure out whether to implement mingw warning equivalent
1279 readline = not_found_dep
1284 ###############################################################
1286 ###############################################################
1288 selinux = not_found_dep
1289 selinuxopt = get_option('selinux')
1290 if meson.version().version_compare('>=0.59')
1291 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1293 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1294 cdata.set('HAVE_LIBSELINUX',
1295 selinux.found() ? 1 : false)
1299 ###############################################################
1301 ###############################################################
1303 systemd = not_found_dep
1304 systemdopt = get_option('systemd')
1305 if meson.version().version_compare('>=0.59')
1306 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1308 systemd = dependency('libsystemd', required: systemdopt)
1309 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1313 ###############################################################
1315 ###############################################################
1318 ssl_library = 'none'
1319 sslopt = get_option('ssl')
1321 if sslopt == 'auto' and auto_features.disabled()
1325 if sslopt in ['auto', 'openssl']
1326 openssl_required = (sslopt == 'openssl')
1328 # Try to find openssl via pkg-config et al, if that doesn't work
1329 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1330 # the library names that we know about.
1332 # via pkg-config et al
1333 ssl = dependency('openssl', required: false)
1334 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1335 # we pass cc.find_library() results if necessary
1338 # via library + headers
1340 ssl_lib = cc.find_library('ssl',
1342 header_include_directories: postgres_inc,
1343 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1344 required: openssl_required)
1345 crypto_lib = cc.find_library('crypto',
1347 required: openssl_required)
1348 if ssl_lib.found() and crypto_lib.found()
1349 ssl_int = [ssl_lib, crypto_lib]
1350 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1352 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1353 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1361 ['CRYPTO_new_ex_data', {'required': true}],
1362 ['SSL_new', {'required': true}],
1364 # Functions introduced in OpenSSL 1.1.0. We used to check for
1365 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1366 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1367 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1369 ['OPENSSL_init_ssl', {'required': true}],
1371 # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1372 ['SSL_CTX_set_cert_cb'],
1374 # Function introduced in OpenSSL 1.1.1, not in LibreSSL.
1375 ['X509_get_signature_info'],
1376 ['SSL_CTX_set_num_tickets'],
1379 are_openssl_funcs_complete = true
1380 foreach c : check_funcs
1382 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1383 required = c.get(1, {}).get('required', false)
1384 if required and not val
1385 are_openssl_funcs_complete = false
1387 error('openssl function @0@ is required'.format(func))
1391 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1395 if are_openssl_funcs_complete
1396 cdata.set('USE_OPENSSL', 1,
1397 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1398 cdata.set('OPENSSL_API_COMPAT', '0x10100000L',
1399 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1400 ssl_library = 'openssl'
1407 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1408 error('no SSL library found')
1413 ###############################################################
1415 ###############################################################
1417 uuidopt = get_option('uuid')
1418 if uuidopt != 'none'
1419 uuidname = uuidopt.to_upper()
1420 if uuidopt == 'e2fs'
1421 uuid = dependency('uuid', required: true)
1422 uuidfunc = 'uuid_generate'
1423 uuidheader = 'uuid/uuid.h'
1424 elif uuidopt == 'bsd'
1425 # libc should have uuid function
1426 uuid = declare_dependency()
1427 uuidfunc = 'uuid_to_string'
1428 uuidheader = 'uuid.h'
1429 elif uuidopt == 'ossp'
1430 # In upstream, the package and library is called just 'uuid', but many
1431 # distros change it to 'ossp-uuid'.
1432 uuid = dependency('ossp-uuid', 'uuid', required: false)
1433 uuidfunc = 'uuid_export'
1434 uuidheader = 'uuid.h'
1436 # Hardcoded lookup for ossp-uuid. This is necessary as ossp-uuid on
1437 # windows installs neither a pkg-config nor a cmake dependency
1438 # information. Nor is there another supported uuid implementation
1439 # available on windows.
1441 uuid = cc.find_library('ossp-uuid',
1442 required: false, dirs: test_lib_d,
1443 has_headers: uuidheader, header_include_directories: postgres_inc)
1446 uuid = cc.find_library('uuid',
1447 required: true, dirs: test_lib_d,
1448 has_headers: uuidheader, header_include_directories: postgres_inc)
1451 error('unknown uuid build option value: @0@'.format(uuidopt))
1454 if not cc.has_header_symbol(uuidheader, uuidfunc,
1456 include_directories: postgres_inc,
1458 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1460 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1462 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1463 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1465 uuid = not_found_dep
1470 ###############################################################
1472 ###############################################################
1474 zlibopt = get_option('zlib')
1475 zlib = not_found_dep
1476 if not zlibopt.disabled()
1477 zlib_t = dependency('zlib', required: zlibopt)
1479 if zlib_t.type_name() == 'internal'
1480 # if fallback was used, we don't need to test if headers are present (they
1481 # aren't built yet, so we can't test)
1483 elif not zlib_t.found()
1484 warning('did not find zlib')
1485 elif not cc.has_header('zlib.h',
1486 args: test_c_args, include_directories: postgres_inc,
1487 dependencies: [zlib_t], required: zlibopt)
1488 warning('zlib header not found')
1494 cdata.set('HAVE_LIBZ', 1)
1500 ###############################################################
1501 # Library: tap test dependencies
1502 ###############################################################
1504 # Check whether tap tests are enabled or not
1505 tap_tests_enabled = false
1506 tapopt = get_option('tap_tests')
1507 if not tapopt.disabled()
1508 # Checking for perl modules for tap tests
1509 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1510 if perl_ipc_run_check.returncode() != 0
1511 message(perl_ipc_run_check.stderr().strip())
1513 error('Additional Perl modules are required to run TAP tests.')
1515 warning('Additional Perl modules are required to run TAP tests.')
1518 tap_tests_enabled = true
1524 ###############################################################
1526 ###############################################################
1528 zstdopt = get_option('zstd')
1529 if not zstdopt.disabled()
1530 zstd = dependency('libzstd', required: false, version: '>=1.4.0')
1531 # Unfortunately the dependency is named differently with cmake
1532 if not zstd.found() # combine with above once meson 0.60.0 is required
1533 zstd = dependency('zstd', required: zstdopt, version: '>=1.4.0',
1534 method: 'cmake', modules: ['zstd::libzstd_shared'])
1538 cdata.set('USE_ZSTD', 1)
1539 cdata.set('HAVE_LIBZSTD', 1)
1543 zstd = not_found_dep
1548 ###############################################################
1550 ###############################################################
1552 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1553 # unnecessarily, because we optionally rely on newer features.
1555 #include <stdbool.h>
1556 #include <complex.h>
1558 #include <inttypes.h>
1560 struct named_init_test {
1565 extern void structfunc(struct named_init_test);
1567 int main(int argc, char **argv)
1569 struct named_init_test nit = {
1574 for (int loop_var = 0; loop_var < 3; loop_var++)
1579 structfunc((struct named_init_test){1, 0});
1585 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1586 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1587 args: test_c_args + ['-std=c99'])
1588 test_c_args += '-std=c99'
1589 cflags += '-std=c99'
1591 error('C compiler does not support C99')
1595 sizeof_long = cc.sizeof('long', args: test_c_args)
1596 cdata.set('SIZEOF_LONG', sizeof_long)
1598 cdata.set('HAVE_LONG_INT_64', 1)
1599 pg_int64_type = 'long int'
1600 cdata.set_quoted('INT64_MODIFIER', 'l')
1601 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1602 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1603 pg_int64_type = 'long long int'
1604 cdata.set_quoted('INT64_MODIFIER', 'll')
1606 error('do not know how to get a 64bit int')
1608 cdata.set('PG_INT64_TYPE', pg_int64_type)
1610 if host_machine.endian() == 'big'
1611 cdata.set('WORDS_BIGENDIAN', 1)
1614 # Determine memory alignment requirements for the basic C data types.
1616 alignof_types = ['short', 'int', 'long', 'double']
1617 foreach t : alignof_types
1618 align = cc.alignment(t, args: test_c_args)
1619 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1622 # Compute maximum alignment of any basic type.
1624 # We require 'double' to have the strictest alignment among the basic types,
1625 # because otherwise the C ABI might impose 8-byte alignment on some of the
1626 # other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
1627 # cause a mismatch between the tuple layout and the C struct layout of a
1628 # catalog tuple. We used to carefully order catalog columns such that any
1629 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1630 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1631 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1633 # We assume without checking that int64's alignment is at least as strong
1634 # as long, char, short, or int. Note that we intentionally do not consider
1635 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1636 # would be too much of a penalty for disk and memory space.
1637 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1638 if cc.alignment(pg_int64_type, args: test_c_args) > alignof_double
1639 error('alignment of int64 is greater than the alignment of double')
1641 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1643 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1644 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1647 # Check if __int128 is a working 128 bit integer type, and if so
1648 # define PG_INT128_TYPE to that typename.
1650 # This currently only detects a GCC/clang extension, but support for other
1651 # environments may be added in the future.
1653 # For the moment we only test for support for 128bit math; support for
1654 # 128bit literals and snprintf is not required.
1657 * We don't actually run this test, just link it to verify that any support
1658 * functions needed for __int128 are present.
1660 * These are globals to discourage the compiler from folding all the
1661 * arithmetic tests down to compile-time constants. We do not have
1662 * convenient support for 128bit literals at this point...
1664 __int128 a = 48828125;
1665 __int128 b = 97656250;
1670 a = (a << 12) + 1; /* 200000000001 */
1671 b = (b << 12) + 5; /* 400000000005 */
1672 /* try the most relevant arithmetic ops */
1675 /* must use the results, else compiler may optimize arithmetic away */
1681 buggy_int128 = false
1683 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1684 # If not cross-compiling, we can test for bugs and disable use of __int128
1685 # with buggy compilers. If cross-compiling, hope for the best.
1686 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1687 if not meson.is_cross_build()
1689 /* This must match the corresponding code in c.h: */
1690 #if defined(__GNUC__) || defined(__SUNPRO_C)
1691 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1692 #elif defined(_MSC_VER)
1693 #define pg_attribute_aligned(a) __declspec(align(a))
1695 typedef __int128 int128a
1696 #if defined(pg_attribute_aligned)
1697 pg_attribute_aligned(8)
1702 void pass_by_val(void *buffer, int128a par) { holder = par; }
1706 long int i64 = 97656225L << 12;
1708 pass_by_val(main, (int128a) i64);
1712 name: '__int128 alignment bug',
1714 assert(r.compiled())
1715 if r.returncode() != 0
1717 message('__int128 support present but buggy and thus disabled')
1722 cdata.set('PG_INT128_TYPE', '__int128')
1723 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1728 # Check if the C compiler knows computed gotos (gcc extension, also
1729 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1731 # Checking whether computed gotos are supported syntax-wise ought to
1732 # be enough, as the syntax is otherwise illegal.
1734 static inline int foo(void)
1736 void *labeladdrs[] = {&&my_label};
1737 goto *labeladdrs[0];
1742 cdata.set('HAVE_COMPUTED_GOTO', 1)
1746 # Check if the C compiler understands _Static_assert(),
1747 # and define HAVE__STATIC_ASSERT if so.
1749 # We actually check the syntax ({ _Static_assert(...) }), because we need
1750 # gcc-style compound expressions to be able to wrap the thing into macros.
1752 int main(int arg, char **argv)
1754 ({ _Static_assert(1, "foo"); });
1758 cdata.set('HAVE__STATIC_ASSERT', 1)
1762 # We use <stdbool.h> if we have it and it declares type bool as having
1763 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1764 if cc.has_type('_Bool', args: test_c_args) \
1765 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1766 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1767 cdata.set('HAVE__BOOL', 1)
1768 cdata.set('PG_USE_STDBOOL', 1)
1772 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1773 # warning for each use of %m.
1774 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1776 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1777 static void call_log(void)
1779 emit_log(0, "error: %s: %m", "foo");
1782 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1783 foreach a : printf_attributes
1784 if cc.compiles(testsrc.format(a),
1785 args: test_c_args + attrib_error_args, name: 'format ' + a)
1786 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1792 if cc.has_function_attribute('visibility:default') and \
1793 cc.has_function_attribute('visibility:hidden')
1794 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1796 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1797 # inlineshidden to C code as well... And either way, we want to put these
1798 # flags into exported files (pgxs, .pc files).
1799 cflags_mod += '-fvisibility=hidden'
1800 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1801 ldflags_mod += '-fvisibility=hidden'
1805 # Check if various builtins exist. Some builtins are tested separately,
1806 # because we want to test something more complicated than the generic case.
1819 foreach builtin : builtins
1820 fname = '__builtin_@0@'.format(builtin)
1821 if cc.has_function(fname, args: test_c_args)
1822 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1827 # Check if the C compiler understands __builtin_types_compatible_p,
1828 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1830 # We check usage with __typeof__, though it's unlikely any compiler would
1831 # have the former and not the latter.
1834 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1836 name: '__builtin_types_compatible_p',
1838 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1842 # Check if the C compiler understands __builtin_$op_overflow(),
1843 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1845 # Check for the most complicated case, 64 bit multiplication, as a
1846 # proxy for all of the operations. To detect the case where the compiler
1847 # knows the function but library support is missing, we must link not just
1848 # compile, and store the results in global variables so the compiler doesn't
1849 # optimize away the call.
1857 return __builtin_mul_overflow(a, b, &result);
1859 name: '__builtin_mul_overflow',
1860 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1862 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1866 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1867 # here. To prevent problems due to two detection methods working, stop
1868 # checking after one.
1871 int main(int arg, char **argv)
1873 unsigned int exx[4] = {0, 0, 0, 0};
1874 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1876 ''', name: '__get_cpuid',
1878 cdata.set('HAVE__GET_CPUID', 1)
1881 int main(int arg, char **argv)
1883 unsigned int exx[4] = {0, 0, 0, 0};
1886 ''', name: '__cpuid',
1888 cdata.set('HAVE__CPUID', 1)
1892 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1895 int main(int arg, char **argv)
1897 unsigned int exx[4] = {0, 0, 0, 0};
1898 __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1900 ''', name: '__get_cpuid_count',
1902 cdata.set('HAVE__GET_CPUID_COUNT', 1)
1905 int main(int arg, char **argv)
1907 unsigned int exx[4] = {0, 0, 0, 0};
1908 __cpuidex(exx, 7, 0);
1910 ''', name: '__cpuidex',
1912 cdata.set('HAVE__CPUIDEX', 1)
1916 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1917 # versions of clang do not understand -fexcess-precision=standard, the use of
1918 # x87 floating point operations leads to problems like isinf possibly returning
1919 # false for a value that is infinite when converted from the 80bit register to
1920 # the 8byte memory representation.
1922 # Only perform the test if the compiler doesn't understand
1923 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1925 if '-fexcess-precision=standard' not in cflags
1926 if not cc.compiles('''
1927 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1930 name: '', args: test_c_args)
1931 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1937 ###############################################################
1939 ###############################################################
1941 common_functional_flags = [
1942 # Disable strict-aliasing rules; needed for gcc 3.3+
1943 '-fno-strict-aliasing',
1944 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1946 '-fexcess-precision=standard',
1949 cflags += cc.get_supported_arguments(common_functional_flags)
1951 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1954 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1955 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1957 common_warning_flags = [
1958 '-Wmissing-prototypes',
1960 # Really don't want VLAs to be used in our dialect of C
1962 # On macOS, complain about usage of symbols newer than the deployment target
1963 '-Werror=unguarded-availability-new',
1965 '-Wmissing-format-attribute',
1966 '-Wimplicit-fallthrough=3',
1967 '-Wcast-function-type',
1968 '-Wshadow=compatible-local',
1969 # This was included in -Wall/-Wformat in older GCC versions
1970 '-Wformat-security',
1973 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1975 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1978 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1979 # the result for them
1980 cflags_no_decl_after_statement = []
1981 if cc.has_argument('-Wdeclaration-after-statement')
1982 cflags_warn += '-Wdeclaration-after-statement'
1983 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1986 # Some code is not clean for -Wmissing-variable-declarations, so we
1987 # make the "no" option available. Also, while clang supports this
1988 # option for C++, gcc does not, so for consistency, leave it off for
1990 cflags_no_missing_var_decls = []
1991 if cc.has_argument('-Wmissing-variable-declarations')
1992 cflags_warn += '-Wmissing-variable-declarations'
1993 cflags_no_missing_var_decls += '-Wno-missing-variable-declarations'
1997 # The following tests want to suppress various unhelpful warnings by adding
1998 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1999 # switches, so we have to test for the positive form and if that works,
2000 # add the negative form.
2002 negative_warning_flags = [
2003 # Suppress clang's unhelpful unused-command-line-argument warnings.
2004 'unused-command-line-argument',
2006 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
2007 # of warnings when building plperl because of usages in the Perl headers.
2008 'compound-token-split-by-macro',
2010 # Similarly disable useless truncation warnings from gcc 8+
2011 'format-truncation',
2012 'stringop-truncation',
2014 # Suppress clang 16's strict warnings about function casts
2015 'cast-function-type-strict',
2017 # To make warning_level=2 / -Wextra work, we'd need at least the following
2019 # 'missing-field-initializers',
2021 # 'unused-parameter',
2024 foreach w : negative_warning_flags
2025 if cc.has_argument('-W' + w)
2026 cflags_warn += '-Wno-' + w
2028 if llvm.found() and cpp.has_argument('-W' + w)
2029 cxxflags_warn += '-Wno-' + w
2034 if cc.get_id() == 'msvc'
2036 '/wd4018', # signed/unsigned mismatch
2037 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
2038 '/wd4273', # inconsistent DLL linkage
2039 '/wd4101', # unreferenced local variable
2040 '/wd4102', # unreferenced label
2041 '/wd4090', # different 'modifier' qualifiers
2042 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
2050 '/D_CRT_SECURE_NO_DEPRECATE',
2051 '/D_CRT_NONSTDC_NO_DEPRECATE',
2054 # We never need export libraries. As link.exe reports their creation, they
2055 # are unnecessarily noisy. Similarly, we don't need import library for
2056 # modules, we only import them dynamically, and they're also noisy.
2058 ldflags_mod += '/NOIMPLIB'
2062 # Compute flags that are built into Meson. We need these to
2063 # substitute into Makefile.global and for pg_config. We only compute
2064 # the flags for Unix-style compilers, since that's the only style that
2065 # would use Makefile.global or pg_config.
2067 # We don't use get_option('warning_level') here, because the other
2068 # warning levels are not useful with PostgreSQL source code.
2069 common_builtin_flags = ['-Wall']
2071 if get_option('debug')
2072 common_builtin_flags += ['-g']
2075 optimization = get_option('optimization')
2076 if optimization == '0'
2077 common_builtin_flags += ['-O0']
2078 elif optimization == '1'
2079 common_builtin_flags += ['-O1']
2080 elif optimization == '2'
2081 common_builtin_flags += ['-O2']
2082 elif optimization == '3'
2083 common_builtin_flags += ['-O3']
2084 elif optimization == 's'
2085 common_builtin_flags += ['-Os']
2088 cflags_builtin = cc.get_supported_arguments(common_builtin_flags)
2090 cxxflags_builtin = cpp.get_supported_arguments(common_builtin_flags)
2095 ###############################################################
2097 ###############################################################
2100 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2101 'desc': '__sync_lock_test_and_set(char)',
2104 __sync_lock_test_and_set(&lock, 1);
2105 __sync_lock_release(&lock);'''},
2107 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2108 'desc': '__sync_lock_test_and_set(int32)',
2111 __sync_lock_test_and_set(&lock, 1);
2112 __sync_lock_release(&lock);'''},
2114 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2115 'desc': '__sync_val_compare_and_swap(int32)',
2118 __sync_val_compare_and_swap(&val, 0, 37);'''},
2120 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2121 'desc': '__sync_val_compare_and_swap(int64)',
2124 __sync_val_compare_and_swap(&val, 0, 37);'''},
2126 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2127 'desc': ' __atomic_compare_exchange_n(int32)',
2131 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2133 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2134 'desc': ' __atomic_compare_exchange_n(int64)',
2138 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2141 foreach check : atomic_checks
2146 }'''.format(check['test'])
2148 cdata.set(check['name'],
2150 name: check['desc'],
2151 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
2156 ###############################################################
2157 # Check for the availability of XSAVE intrinsics.
2158 ###############################################################
2161 if host_cpu == 'x86' or host_cpu == 'x86_64'
2164 #include <immintrin.h>
2168 return _xgetbv(0) & 0xe0;
2172 if cc.links(prog, name: 'XSAVE intrinsics without -mxsave',
2174 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2175 elif cc.links(prog, name: 'XSAVE intrinsics with -mxsave',
2176 args: test_c_args + ['-mxsave'])
2177 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2178 cflags_xsave += '-mxsave'
2184 ###############################################################
2185 # Check for the availability of AVX-512 popcount intrinsics.
2186 ###############################################################
2189 if host_cpu == 'x86_64'
2192 #include <immintrin.h>
2196 const char buf[sizeof(__m512i)];
2198 __m512i accum = _mm512_setzero_si512();
2199 const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2200 const __m512i cnt = _mm512_popcnt_epi64(val);
2201 accum = _mm512_add_epi64(accum, cnt);
2202 popcnt = _mm512_reduce_add_epi64(accum);
2203 /* return computed value, to prevent the above being optimized away */
2208 if cc.links(prog, name: 'AVX-512 popcount without -mavx512vpopcntdq -mavx512bw',
2209 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))])
2210 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2211 elif cc.links(prog, name: 'AVX-512 popcount with -mavx512vpopcntdq -mavx512bw',
2212 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))] + ['-mavx512vpopcntdq'] + ['-mavx512bw'])
2213 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2214 cflags_popcnt += ['-mavx512vpopcntdq'] + ['-mavx512bw']
2220 ###############################################################
2221 # Select CRC-32C implementation.
2223 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2224 # use the special CRC instructions for calculating CRC-32C. If we're not
2225 # targeting such a processor, but we can nevertheless produce code that uses
2226 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
2227 # implementations and select which one to use at runtime, depending on whether
2228 # SSE 4.2 is supported by the processor we're running on.
2230 # Similarly, if we are targeting an ARM processor that has the CRC
2231 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2232 # we're not targeting such a processor, but can nevertheless produce code that
2233 # uses the CRC instructions, compile both, and select at runtime.
2234 ###############################################################
2236 have_optimized_crc = false
2238 if host_cpu == 'x86' or host_cpu == 'x86_64'
2240 if cc.get_id() == 'msvc'
2241 cdata.set('USE_SSE42_CRC32C', false)
2242 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2243 have_optimized_crc = true
2247 #include <nmmintrin.h>
2251 unsigned int crc = 0;
2252 crc = _mm_crc32_u8(crc, 0);
2253 crc = _mm_crc32_u32(crc, 0);
2254 /* return computed value, to prevent the above being optimized away */
2259 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2261 # Use Intel SSE 4.2 unconditionally.
2262 cdata.set('USE_SSE42_CRC32C', 1)
2263 have_optimized_crc = true
2264 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2265 args: test_c_args + ['-msse4.2'])
2266 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2267 # the runtime check.
2268 cflags_crc += '-msse4.2'
2269 cdata.set('USE_SSE42_CRC32C', false)
2270 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2271 have_optimized_crc = true
2276 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2279 #include <arm_acle.h>
2283 unsigned int crc = 0;
2284 crc = __crc32cb(crc, 0);
2285 crc = __crc32ch(crc, 0);
2286 crc = __crc32cw(crc, 0);
2287 crc = __crc32cd(crc, 0);
2289 /* return computed value, to prevent the above being optimized away */
2294 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2296 # Use ARM CRC Extension unconditionally
2297 cdata.set('USE_ARMV8_CRC32C', 1)
2298 have_optimized_crc = true
2299 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2300 args: test_c_args + ['-march=armv8-a+crc'])
2301 # Use ARM CRC Extension, with runtime check
2302 cflags_crc += '-march=armv8-a+crc'
2303 cdata.set('USE_ARMV8_CRC32C', false)
2304 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2305 have_optimized_crc = true
2308 elif host_cpu == 'loongarch64'
2313 unsigned int crc = 0;
2314 crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2315 crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2316 crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2317 crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2319 /* return computed value, to prevent the above being optimized away */
2324 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',
2326 # Use LoongArch CRC instruction unconditionally
2327 cdata.set('USE_LOONGARCH_CRC32C', 1)
2328 have_optimized_crc = true
2333 if not have_optimized_crc
2334 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2336 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2341 ###############################################################
2342 # Other CPU specific stuff
2343 ###############################################################
2345 if host_cpu == 'x86_64'
2350 long long x = 1; long long r;
2351 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2353 name: '@0@: popcntq instruction'.format(host_cpu),
2355 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2358 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2359 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2360 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2363 addi(int ra, int si)
2366 if (__builtin_constant_p(si))
2367 __asm__ __volatile__(
2368 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2371 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2374 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2381 ###############################################################
2382 # Library / OS tests
2383 ###############################################################
2385 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2386 # unnecessary checks over and over, particularly on windows.
2399 'sys/personality.h',
2408 foreach header : header_checks
2409 varname = 'HAVE_' + header.underscorify().to_upper()
2411 # Emulate autoconf behaviour of not-found->undef, found->1
2412 found = cc.has_header(header,
2413 include_directories: postgres_inc, args: test_c_args)
2414 cdata.set(varname, found ? 1 : false,
2415 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2420 ['F_FULLFSYNC', 'fcntl.h'],
2421 ['fdatasync', 'unistd.h'],
2422 ['posix_fadvise', 'fcntl.h'],
2423 ['strlcat', 'string.h'],
2424 ['strlcpy', 'string.h'],
2425 ['strnlen', 'string.h'],
2426 ['strsep', 'string.h'],
2429 # Need to check for function declarations for these functions, because
2430 # checking for library symbols wouldn't handle deployment target
2431 # restrictions on macOS
2433 ['preadv', 'sys/uio.h'],
2434 ['pwritev', 'sys/uio.h'],
2437 # Check presence of some optional LLVM functions.
2440 ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2441 ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2445 foreach c : decl_checks
2449 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2451 found = cc.has_header_symbol(header, func,
2452 args: test_c_args, include_directories: postgres_inc,
2454 cdata.set10(varname, found, description:
2455 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2456 don't.'''.format(func))
2460 if cc.has_type('struct option',
2461 args: test_c_args, include_directories: postgres_inc,
2462 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2463 cdata.set('HAVE_STRUCT_OPTION', 1)
2467 foreach c : ['opterr', 'optreset']
2468 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2477 '''.format(c), name: c, args: test_c_args)
2478 cdata.set(varname, 1)
2480 cdata.set(varname, false)
2484 if cc.has_type('socklen_t',
2485 args: test_c_args, include_directories: postgres_inc,
2487 #include <sys/socket.h>''')
2488 cdata.set('HAVE_SOCKLEN_T', 1)
2491 if cc.has_member('struct sockaddr', 'sa_len',
2492 args: test_c_args, include_directories: postgres_inc,
2494 #include <sys/types.h>
2495 #include <sys/socket.h>''')
2496 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2499 if cc.has_member('struct tm', 'tm_zone',
2500 args: test_c_args, include_directories: postgres_inc,
2502 #include <sys/types.h>
2505 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2510 extern int foo(void);
2513 return timezone / 60;
2516 name: 'global variable `timezone\' exists',
2517 args: test_c_args, include_directories: postgres_inc)
2518 cdata.set('HAVE_INT_TIMEZONE', 1)
2520 cdata.set('HAVE_INT_TIMEZONE', false)
2523 if cc.has_type('union semun',
2525 include_directories: postgres_inc,
2527 #include <sys/types.h>
2528 #include <sys/ipc.h>
2529 #include <sys/sem.h>
2531 cdata.set('HAVE_UNION_SEMUN', 1)
2539 switch (strerror_r(1, buf, sizeof(buf)))
2540 { case 0: break; default: break; }
2543 args: test_c_args, include_directories: postgres_inc)
2544 cdata.set('STRERROR_R_INT', 1)
2546 cdata.set('STRERROR_R_INT', false)
2549 # Find the right header file for the locale_t type. macOS needs xlocale.h;
2550 # standard is locale.h, but glibc <= 2.25 also had an xlocale.h file that
2551 # we should not use so we check the standard header first. MSVC has a
2552 # replacement defined in src/include/port/win32_port.h.
2553 if not cc.has_type('locale_t', prefix: '#include <locale.h>') and \
2554 cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2555 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2558 # Check if the C compiler understands typeof or a variant. Define
2559 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2560 foreach kw : ['typeof', '__typeof__', 'decltype']
2571 args: test_c_args, include_directories: postgres_inc)
2573 cdata.set('HAVE_TYPEOF', 1)
2575 cdata.set('typeof', kw)
2583 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2584 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2585 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2586 wcstombs_l_test = '''
2598 if (not cc.compiles(wcstombs_l_test.format(''),
2599 name: 'wcstombs_l') and
2600 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2601 name: 'wcstombs_l in xlocale.h'))
2602 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2606 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2607 # understands, because it conflicts with __declspec(restrict). Therefore we
2608 # define pg_restrict to the appropriate definition, which presumably won't
2611 # We assume C99 support, so we don't need to make this conditional.
2612 cdata.set('pg_restrict', '__restrict')
2615 # Most libraries are included only if they demonstrably provide a function we
2616 # need, but libm is an exception: always include it, because there are too
2617 # many compilers that play cute optimization games that will break probes for
2618 # standard functions such as pow().
2619 os_deps += cc.find_library('m', required: false)
2621 rt_dep = cc.find_library('rt', required: false)
2623 dl_dep = cc.find_library('dl', required: false)
2625 util_dep = cc.find_library('util', required: false)
2627 getopt_dep = cc.find_library('getopt', required: false)
2628 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2629 # Check if we want to replace getopt/getopt_long even if provided by the system
2630 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2631 # so always use our version on Windows
2632 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2633 # (i.e., allow '-' as a flag character), so use our version on those platforms
2634 # - We want to use system's getopt_long() only if the system provides struct
2636 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2637 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2640 execinfo_dep = cc.find_library('execinfo', required: false)
2642 if host_system == 'cygwin'
2643 cygipc_dep = cc.find_library('cygipc', required: false)
2645 cygipc_dep = not_found_dep
2648 if host_system == 'sunos'
2649 socket_dep = cc.find_library('socket', required: false)
2651 socket_dep = not_found_dep
2654 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2655 # unnecessary checks over and over, particularly on windows.
2657 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2658 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2659 ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2661 ['copy_file_range'],
2662 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2663 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2664 # required. Just checking for dlsym() ought to suffice.
2665 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2668 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2669 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2679 ['posix_fallocate'],
2681 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2682 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2683 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2684 ['setproctitle', {'dependencies': [util_dep]}],
2685 ['setproctitle_fast'],
2686 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2687 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2688 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2689 ['socket', {'dependencies': [socket_dep], 'define': false}],
2691 ['strerror_r', {'dependencies': [thread_dep]}],
2697 ['sync_file_range'],
2703 func_check_results = {}
2704 foreach c : func_checks
2706 kwargs = c.get(1, {})
2707 deps = kwargs.get('dependencies', [])
2709 if kwargs.get('skip', false)
2713 found = cc.has_function(func, args: test_c_args)
2720 found = cc.has_function(func, args: test_c_args,
2721 dependencies: [dep])
2729 func_check_results += {func: found}
2731 if kwargs.get('define', true)
2732 # Emulate autoconf behaviour of not-found->undef, found->1
2733 cdata.set('HAVE_' + func.underscorify().to_upper(),
2735 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2740 if cc.has_function('syslog', args: test_c_args) and \
2741 cc.check_header('syslog.h', args: test_c_args)
2742 cdata.set('HAVE_SYSLOG', 1)
2746 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2748 if sema_kind == 'unnamed_posix' and \
2749 not func_check_results.get('sem_init', false)
2753 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2754 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2756 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2757 cdata.set_quoted('DLSUFFIX', dlsuffix)
2760 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2761 cdata.set_quoted('PG_VERSION_STR',
2762 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2763 pg_version, host_machine.cpu_family(), host_system,
2764 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2769 ###############################################################
2771 ###############################################################
2773 nlsopt = get_option('nls')
2774 libintl = not_found_dep
2776 if not nlsopt.disabled()
2777 # otherwise there'd be lots of
2778 # "Gettext not found, all translation (po) targets will be ignored."
2779 # warnings if not found.
2780 msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2782 # meson 0.59 has this wrapped in dependency('intl')
2783 if (msgfmt.found() and
2784 cc.check_header('libintl.h', required: nlsopt,
2785 args: test_c_args, include_directories: postgres_inc))
2788 if cc.has_function('ngettext')
2789 libintl = declare_dependency()
2791 libintl = cc.find_library('intl',
2792 has_headers: ['libintl.h'], required: nlsopt,
2793 header_include_directories: postgres_inc,
2799 i18n = import('i18n')
2800 cdata.set('ENABLE_NLS', 1)
2806 ###############################################################
2808 ###############################################################
2810 # Set up compiler / linker arguments to be used everywhere, individual targets
2811 # can add further args directly, or indirectly via dependencies
2812 add_project_arguments(cflags, language: ['c'])
2813 add_project_arguments(cppflags, language: ['c'])
2814 add_project_arguments(cflags_warn, language: ['c'])
2815 add_project_arguments(cxxflags, language: ['cpp'])
2816 add_project_arguments(cppflags, language: ['cpp'])
2817 add_project_arguments(cxxflags_warn, language: ['cpp'])
2818 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2821 # Collect a number of lists of things while recursing through the source
2822 # tree. Later steps then can use those.
2824 # list of targets for various alias targets
2825 backend_targets = []
2828 contrib_targets = []
2829 testprep_targets = []
2833 # Define the tests to distribute them to the correct test styles later
2838 # Default options for targets
2840 # First identify rpaths
2841 bin_install_rpaths = []
2842 lib_install_rpaths = []
2843 mod_install_rpaths = []
2846 # Don't add rpaths on darwin for now - as long as only absolute references to
2847 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2848 # their final destination.
2849 if host_system != 'darwin'
2850 # Add absolute path to libdir to rpath. This ensures installed binaries /
2851 # libraries find our libraries (mainly libpq).
2852 bin_install_rpaths += dir_prefix / dir_lib
2853 lib_install_rpaths += dir_prefix / dir_lib
2854 mod_install_rpaths += dir_prefix / dir_lib
2856 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2858 # Not needed on darwin even if we use relative rpaths for our own libraries,
2859 # as the install_name of libraries in extra_lib_dirs will point to their
2861 bin_install_rpaths += postgres_lib_d
2862 lib_install_rpaths += postgres_lib_d
2863 mod_install_rpaths += postgres_lib_d
2867 # Define arguments for default targets
2869 default_target_args = {
2870 'implicit_include_directories': false,
2874 default_lib_args = default_target_args + {
2878 internal_lib_args = default_lib_args + {
2879 'build_by_default': false,
2883 default_mod_args = default_lib_args + {
2885 'install_dir': dir_lib_pkg,
2888 default_bin_args = default_target_args + {
2889 'install_dir': dir_bin,
2892 if get_option('rpath')
2893 default_lib_args += {
2894 'install_rpath': ':'.join(lib_install_rpaths),
2897 default_mod_args += {
2898 'install_rpath': ':'.join(mod_install_rpaths),
2901 default_bin_args += {
2902 'install_rpath': ':'.join(bin_install_rpaths),
2907 # Helper for exporting a limited number of symbols
2908 gen_export_kwargs = {
2909 'input': 'exports.txt',
2910 'output': '@BASENAME@.'+export_file_suffix,
2911 'command': [perl, files('src/tools/gen_export.pl'),
2912 '--format', export_file_format,
2913 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2914 'build_by_default': false,
2921 ### Helpers for custom targets used across the tree
2924 catalog_pm = files('src/backend/catalog/Catalog.pm')
2925 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2926 gen_kwlist_deps = [perfect_hash_pm]
2928 perl, '-I', '@SOURCE_ROOT@/src/tools',
2929 files('src/tools/gen_keywordlist.pl'),
2930 '--output', '@OUTDIR@', '@INPUT@']
2935 ### windows resources related stuff
2938 if host_system == 'windows'
2939 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2940 win32ver_rc = files('src/port/win32ver.rc')
2941 rcgen = find_program('src/tools/rcgen', native: true)
2944 '--srcdir', '@SOURCE_DIR@',
2945 '--builddir', meson.build_root(),
2946 '--rcout', '@OUTPUT0@',
2947 '--out', '@OUTPUT1@',
2948 '--input', '@INPUT@',
2952 if cc.get_argument_syntax() == 'msvc'
2953 rc = find_program('rc', required: true)
2954 rcgen_base_args += ['--rc', rc.path()]
2955 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2957 windres = find_program('windres', required: true)
2958 rcgen_base_args += ['--windres', windres.path()]
2959 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2962 # msbuild backend doesn't support this atm
2963 if meson.backend() == 'ninja'
2964 rcgen_base_args += ['--depfile', '@DEPFILE@']
2967 rcgen_bin_args = rcgen_base_args + [
2968 '--VFT_TYPE', 'VFT_APP',
2969 '--FILEENDING', 'exe',
2973 rcgen_lib_args = rcgen_base_args + [
2974 '--VFT_TYPE', 'VFT_DLL',
2975 '--FILEENDING', 'dll',
2978 rc_bin_gen = generator(rcgen,
2979 depfile: '@BASENAME@.d',
2980 arguments: rcgen_bin_args,
2981 output: rcgen_outputs,
2984 rc_lib_gen = generator(rcgen,
2985 depfile: '@BASENAME@.d',
2986 arguments: rcgen_lib_args,
2987 output: rcgen_outputs,
2993 # headers that the whole build tree depends on
2994 generated_headers = []
2995 # headers that the backend build depends on
2996 generated_backend_headers = []
2997 # configure_files() output, needs a way of converting to file names
2998 configure_files = []
3000 # generated files that might conflict with a partial in-tree autoconf build
3001 generated_sources = []
3002 # same, for paths that differ between autoconf / meson builds
3003 # elements are [dir, [files]]
3004 generated_sources_ac = {}
3007 # First visit src/include - all targets creating headers are defined
3008 # within. That makes it easy to add the necessary dependencies for the
3009 # subsequent build steps.
3011 subdir('src/include')
3015 # Then through src/port and src/common, as most other things depend on them
3017 frontend_port_code = declare_dependency(
3018 compile_args: ['-DFRONTEND'],
3019 include_directories: [postgres_inc],
3020 dependencies: os_deps,
3023 backend_port_code = declare_dependency(
3024 compile_args: ['-DBUILDING_DLL'],
3025 include_directories: [postgres_inc],
3026 sources: [errcodes], # errcodes.h is needed due to use of ereport
3027 dependencies: os_deps,
3032 frontend_common_code = declare_dependency(
3033 compile_args: ['-DFRONTEND'],
3034 include_directories: [postgres_inc],
3035 sources: generated_headers,
3036 dependencies: [os_deps, zlib, zstd, lz4],
3039 backend_common_code = declare_dependency(
3040 compile_args: ['-DBUILDING_DLL'],
3041 include_directories: [postgres_inc],
3042 sources: generated_headers,
3043 dependencies: [os_deps, zlib, zstd],
3046 subdir('src/common')
3048 # all shared libraries should depend on shlib_code
3049 shlib_code = declare_dependency(
3050 link_args: ldflags_sl,
3053 # all static libraries not part of the backend should depend on this
3054 frontend_stlib_code = declare_dependency(
3055 include_directories: [postgres_inc],
3056 link_with: [common_static, pgport_static],
3057 sources: generated_headers,
3058 dependencies: [os_deps, libintl],
3061 # all shared libraries not part of the backend should depend on this
3062 frontend_shlib_code = declare_dependency(
3063 include_directories: [postgres_inc],
3064 link_with: [common_shlib, pgport_shlib],
3065 sources: generated_headers,
3066 dependencies: [shlib_code, os_deps, libintl],
3069 # Dependencies both for static and shared libpq
3079 subdir('src/interfaces/libpq')
3080 # fe_utils depends on libpq
3081 subdir('src/fe_utils')
3083 # for frontend binaries
3084 frontend_code = declare_dependency(
3085 include_directories: [postgres_inc],
3086 link_with: [fe_utils, common_static, pgport_static],
3087 sources: generated_headers,
3088 dependencies: [os_deps, libintl],
3091 backend_both_deps += [
3108 backend_mod_deps = backend_both_deps + os_deps
3110 backend_code = declare_dependency(
3111 compile_args: ['-DBUILDING_DLL'],
3112 include_directories: [postgres_inc],
3113 link_args: ldflags_be,
3115 sources: generated_headers + generated_backend_headers,
3116 dependencies: os_deps + backend_both_deps + backend_deps,
3119 # install these files only during test, not main install
3120 test_install_data = []
3121 test_install_libs = []
3123 # src/backend/meson.build defines backend_mod_code used for extension
3127 # Then through the main sources. That way contrib can have dependencies on
3128 # main sources. Note that this explicitly doesn't enter src/test, right now a
3129 # few regression tests depend on contrib files.
3136 subdir('src/interfaces/libpq/test')
3137 subdir('src/interfaces/ecpg/test')
3139 subdir('doc/src/sgml')
3141 generated_sources_ac += {'': ['GNUmakefile']}
3143 # After processing src/test, add test_install_libs to the testprep_targets
3145 testprep_targets += test_install_libs
3148 # If there are any files in the source directory that we also generate in the
3149 # build directory, they might get preferred over the newly generated files,
3150 # e.g. because of a #include "file", which always will search in the current
3152 message('checking for file conflicts between source and build directory')
3153 conflicting_files = []
3154 potentially_conflicting_files_t = []
3155 potentially_conflicting_files_t += generated_headers
3156 potentially_conflicting_files_t += generated_backend_headers
3157 potentially_conflicting_files_t += generated_backend_sources
3158 potentially_conflicting_files_t += generated_sources
3160 potentially_conflicting_files = []
3162 # convert all sources of potentially conflicting files into uniform shape
3163 foreach t : potentially_conflicting_files_t
3164 potentially_conflicting_files += t.full_path()
3166 foreach t1 : configure_files
3167 if meson.version().version_compare('>=0.59')
3168 t = fs.parent(t1) / fs.name(t1)
3170 t = '@0@'.format(t1)
3172 potentially_conflicting_files += meson.current_build_dir() / t
3174 foreach sub, fnames : generated_sources_ac
3175 sub = meson.build_root() / sub
3176 foreach fname : fnames
3177 potentially_conflicting_files += sub / fname
3181 # find and report conflicting files
3182 foreach build_path : potentially_conflicting_files
3183 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3184 # str.replace is in 0.56
3185 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3186 if fs.exists(src_path) or fs.is_symlink(src_path)
3187 conflicting_files += src_path
3190 # XXX: Perhaps we should generate a file that would clean these up? The list
3192 if conflicting_files.length() > 0
3193 errmsg_cleanup = '''
3194 Conflicting files in source directory:
3197 The conflicting files need to be removed, either by removing the files listed
3198 above, or by running configure and then make maintainer-clean.
3200 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3201 error(errmsg_nonclean_base.format(errmsg_cleanup))
3206 ###############################################################
3208 ###############################################################
3211 # We want to define additional install targets beyond what meson provides. For
3212 # that we need to define targets depending on nearly everything. We collected
3213 # the results of i18n.gettext() invocations into nls_targets, that also
3214 # includes maintainer targets though. Collect the ones we want as a dependency.
3216 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3217 # generation happens during install, so that's not a real issue.
3219 if libintl.found() and meson.version().version_compare('>=0.60')
3220 # use range() to avoid the flattening of the list that foreach() would do
3221 foreach off : range(0, nls_targets.length())
3222 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3223 # -pot target 3) maintainer -pot target
3224 nls_mo_targets += nls_targets[off][0]
3226 alias_target('nls', nls_mo_targets)
3241 # Meson's default install target is quite verbose. Provide one that is quiet.
3242 install_quiet = custom_target('install-quiet',
3243 output: 'install-quiet',
3244 build_always_stale: true,
3245 build_by_default: false,
3246 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3250 # Target to install files used for tests, which aren't installed by default
3251 install_test_files_args = [
3253 '--prefix', dir_prefix,
3254 '--install', contrib_data_dir, test_install_data,
3255 '--install', dir_lib_pkg, test_install_libs,
3257 run_target('install-test-files',
3258 command: [python] + install_test_files_args,
3259 depends: testprep_targets,
3264 ###############################################################
3266 ###############################################################
3268 # DESTDIR for the installation we'll run tests in
3269 test_install_destdir = meson.build_root() / 'tmp_install/'
3271 # DESTDIR + prefix appropriately munged
3272 if build_system != 'windows'
3273 # On unixoid systems this is trivial, we just prepend the destdir
3274 assert(dir_prefix.startswith('/')) # enforced by meson
3275 temp_install_bindir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_bin)
3276 temp_install_libdir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_lib)
3278 # drives, drive-relative paths, etc make this complicated on windows, call
3279 # into a copy of meson's logic for it
3282 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3283 test_install_destdir]
3284 temp_install_bindir = run_command(command, dir_prefix / dir_bin, check: true).stdout().strip()
3285 temp_install_libdir = run_command(command, dir_prefix / dir_lib, check: true).stdout().strip()
3288 meson_install_args = meson_args + ['install'] + {
3289 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3293 # setup tests should be run first,
3294 # so define priority for these
3295 setup_tests_priority = 100
3297 meson_bin, args: meson_install_args ,
3298 env: {'DESTDIR':test_install_destdir},
3299 priority: setup_tests_priority,
3304 test('install_test_files',
3306 args: install_test_files_args + ['--destdir', test_install_destdir],
3307 priority: setup_tests_priority,
3311 test_result_dir = meson.build_root() / 'testrun'
3314 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3315 # inevitable conflicts from running tests in parallel, hackishly assign
3316 # different ports for different tests.
3320 test_env = environment()
3322 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3323 test_env.set('PG_REGRESS', pg_regress.full_path())
3324 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3325 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3327 # Test suites that are not safe by default but can be run if selected
3328 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3329 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3330 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3332 # Add the temporary installation to the library search path on platforms where
3333 # that works (everything but windows, basically). On windows everything
3334 # library-like gets installed into bindir, solving that issue.
3335 if library_path_var != ''
3336 test_env.prepend(library_path_var, temp_install_libdir)
3340 # Create (and remove old) initdb template directory. Tests use that, where
3341 # possible, to make it cheaper to run tests.
3343 # Use python to remove the old cached initdb, as we cannot rely on a working
3344 # 'rm' binary on windows.
3345 test('initdb_cache',
3353 shutil.rmtree(sys.argv[1], ignore_errors=True)
3354 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3355 sys.exit(sp.returncode)
3357 test_initdb_template,
3358 temp_install_bindir / 'initdb',
3359 '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3362 priority: setup_tests_priority - 1,
3370 ###############################################################
3372 ###############################################################
3374 # When using a meson version understanding exclude_suites, define a
3375 # 'tmp_install' test setup (the default) that excludes tests running against a
3376 # pre-existing install and a 'running' setup that conflicts with creation of
3377 # the temporary installation and tap tests (which don't support running
3378 # against a running server).
3382 if meson.version().version_compare('>=0.57')
3385 runningcheck = false
3388 testwrap = files('src/tools/testwrap')
3390 foreach test_dir : tests
3393 '--basedir', meson.build_root(),
3394 '--srcdir', test_dir['sd'],
3397 foreach kind, v : test_dir
3398 if kind in ['sd', 'bd', 'name']
3404 if kind in ['regress', 'isolation', 'ecpg']
3405 if kind == 'regress'
3407 fallback_dbname = 'regression_@0@'
3408 elif kind == 'isolation'
3409 runner = pg_isolation_regress
3410 fallback_dbname = 'isolation_regression_@0@'
3412 runner = pg_regress_ecpg
3413 fallback_dbname = 'ecpg_regression_@0@'
3416 test_group = test_dir['name']
3417 test_group_running = test_dir['name'] + '-running'
3419 test_output = test_result_dir / test_group / kind
3420 test_output_running = test_result_dir / test_group_running/ kind
3422 # Unless specified by the test, choose a non-conflicting database name,
3423 # to avoid conflicts when running against existing server.
3424 dbname = t.get('dbname',
3425 fallback_dbname.format(test_dir['name']))
3427 test_command_base = [
3429 '--inputdir', t.get('inputdir', test_dir['sd']),
3430 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3432 '--dlpath', test_dir['bd'],
3433 '--max-concurrent-tests=20',
3435 ] + t.get('regress_args', [])
3438 if t.has_key('schedule')
3439 test_selection += ['--schedule', t['schedule'],]
3442 if kind == 'isolation'
3443 test_selection += t.get('specs', [])
3445 test_selection += t.get('sql', [])
3449 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3455 'depends': test_deps + t.get('deps', []),
3457 } + t.get('test_kwargs', {})
3459 test(test_group / kind,
3463 '--testgroup', test_group,
3467 '--outputdir', test_output,
3468 '--temp-instance', test_output / 'tmp_check',
3469 '--port', testport.to_string(),
3473 kwargs: test_kwargs,
3475 install_suites += test_group
3477 # some tests can't support running against running DB
3478 if runningcheck and t.get('runningcheck', true)
3479 test(test_group_running / kind,
3483 '--testgroup', test_group_running,
3487 '--outputdir', test_output_running,
3490 is_parallel: t.get('runningcheck-parallel', true),
3491 suite: test_group_running,
3492 kwargs: test_kwargs,
3494 running_suites += test_group_running
3499 testwrap_tap = testwrap_base
3500 if not tap_tests_enabled
3501 testwrap_tap += ['--skip', 'TAP tests not enabled']
3506 '-I', meson.source_root() / 'src/test/perl',
3507 '-I', test_dir['sd'],
3510 # Add temporary install, the build directory for non-installed binaries and
3511 # also test/ for non-installed test binaries built separately.
3513 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3515 foreach name, value : t.get('env', {})
3516 env.set(name, value)
3519 test_group = test_dir['name']
3522 'suite': test_group,
3524 'depends': test_deps + t.get('deps', []),
3526 } + t.get('test_kwargs', {})
3528 foreach onetap : t['tests']
3529 # Make tap test names prettier, remove t/ and .pl
3531 if onetap_p.startswith('t/')
3532 onetap_p = onetap.split('t/')[1]
3534 if onetap_p.endswith('.pl')
3535 onetap_p = fs.stem(onetap_p)
3538 test(test_dir['name'] / onetap_p,
3540 kwargs: test_kwargs,
3541 args: testwrap_tap + [
3542 '--testgroup', test_dir['name'],
3543 '--testname', onetap_p,
3545 test_dir['sd'] / onetap,
3549 install_suites += test_group
3551 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3554 endforeach # kinds of tests
3556 endforeach # directories with tests
3558 # repeat condition so meson realizes version dependency
3559 if meson.version().version_compare('>=0.57')
3560 add_test_setup('tmp_install',
3562 exclude_suites: running_suites)
3563 add_test_setup('running',
3564 exclude_suites: ['setup'] + install_suites)
3569 ###############################################################
3571 ###############################################################
3573 alias_target('backend', backend_targets)
3574 alias_target('bin', bin_targets + [libpq_st])
3575 alias_target('pl', pl_targets)
3576 alias_target('contrib', contrib_targets)
3577 alias_target('testprep', testprep_targets)
3579 alias_target('world', all_built, docs)
3580 alias_target('install-world', install_quiet, installdocs)
3584 perl, '-ne', 'next if /^#/; print',
3585 files('doc/src/sgml/targets-meson.txt'),
3591 ###############################################################
3592 # Distribution archive
3593 ###############################################################
3595 # Meson has its own distribution building command (meson dist), but we
3596 # are not using that at this point. The main problem is that, the way
3597 # they have implemented it, it is not deterministic. Also, we want it
3598 # to be equivalent to the "make" version for the time being. But the
3599 # target name "dist" in meson is reserved for that reason, so we call
3600 # the custom target "pgdist".
3602 git = find_program('git', required: false, native: true, disabler: true)
3603 bzip2 = find_program('bzip2', required: false, native: true)
3605 distdir = meson.project_name() + '-' + meson.project_version()
3607 pg_git_revision = get_option('PG_GIT_REVISION')
3609 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3610 # in case the environment has a different setting. Without this, a
3611 # tarball created on Windows might be different than on, and unusable
3612 # on, Unix machines.
3614 tar_gz = custom_target('tar.gz',
3615 build_always_stale: true,
3616 command: [git, '-C', '@SOURCE_ROOT@',
3617 '-c', 'core.autocrlf=false',
3619 '--format', 'tar.gz',
3621 '--prefix', distdir + '/',
3622 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3624 output: distdir + '.tar.gz',
3628 tar_bz2 = custom_target('tar.bz2',
3629 build_always_stale: true,
3630 command: [git, '-C', '@SOURCE_ROOT@',
3631 '-c', 'core.autocrlf=false',
3632 '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3634 '--format', 'tar.bz2',
3635 '--prefix', distdir + '/',
3636 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3638 output: distdir + '.tar.bz2',
3641 tar_bz2 = custom_target('tar.bz2',
3642 command: [perl, '-e', 'exit 1'],
3643 output: distdir + '.tar.bz2',
3647 alias_target('pgdist', [tar_gz, tar_bz2])
3649 # Make the standard "dist" command fail, to prevent accidental use.
3650 # But not if we are in a subproject, in case the parent project wants to
3651 # create a dist using the standard Meson command.
3652 if not meson.is_subproject()
3653 # We can only pass the identifier perl here when we depend on >= 0.55
3654 if meson.version().version_compare('>=0.55')
3655 meson.add_dist_script(perl, '-e', 'exit 1')
3661 ###############################################################
3662 # The End, The End, My Friend
3663 ###############################################################
3665 if meson.version().version_compare('>=0.57')
3669 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3670 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3671 'segment size': get_option('segsize_blocks') != 0 ?
3672 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3673 '@0@ GB'.format(get_option('segsize')),
3675 section: 'Data layout',
3680 'host system': '@0@ @1@'.format(host_system, host_cpu),
3681 'build system': '@0@ @1@'.format(build_machine.system(),
3682 build_machine.cpu_family()),
3689 'linker': '@0@'.format(cc.get_linker_id()),
3690 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3692 section: 'Compiler',
3697 'CPP FLAGS': ' '.join(cppflags),
3698 'C FLAGS, functional': ' '.join(cflags),
3699 'C FLAGS, warnings': ' '.join(cflags_warn),
3700 'C FLAGS, modules': ' '.join(cflags_mod),
3701 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3702 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3704 section: 'Compiler Flags',
3710 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3712 section: 'Compiler',
3717 'C++ FLAGS, functional': ' '.join(cxxflags),
3718 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3719 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3721 section: 'Compiler Flags',
3727 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3729 'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3731 section: 'Programs',
3737 'bsd_auth': bsd_auth,
3739 'docs_pdf': docs_pdf_dep,
3751 'plpython': python3_dep,
3753 'readline': readline,
3760 section: 'External libraries',