]> git.ipfire.org Git - thirdparty/postgresql.git/blob - meson.build
Doc: fix prompt in psql crosstabview example
[thirdparty/postgresql.git] / meson.build
1 # Copyright (c) 2022-2024, PostgreSQL Global Development Group
2
3 # Entry point for building PostgreSQL with meson
4 #
5 # Good starting points for writing meson.build files are:
6 # - https://mesonbuild.com/Syntax.html
7 # - https://mesonbuild.com/Reference-manual.html
8
9 project('postgresql',
10 ['c'],
11 version: '17devel',
12 license: 'PostgreSQL',
13
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',
18 default_options: [
19 'warning_level=1', #-Wall equivalent
20 'b_pch=false',
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',
26 ]
27 )
28
29
30
31 ###############################################################
32 # Basic prep
33 ###############################################################
34
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
37
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
41
42 cc = meson.get_compiler('c')
43
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
46 auto_features = get_option('auto_features')
47
48
49
50 ###############################################################
51 # Safety first
52 ###############################################################
53
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.
57 #
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 = '''
64 ****
65 Non-clean source code directory detected.
66
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.
71
72 @0@
73 ****'''
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))
77 endif
78
79
80
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
84
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
87
88 postgres_lib_d = get_option('extra_lib_dirs')
89
90 cppflags = []
91
92 cflags = []
93 cxxflags = []
94 cflags_warn = []
95 cxxflags_warn = []
96 cflags_mod = []
97 cxxflags_mod = []
98
99 ldflags = []
100 ldflags_be = []
101 ldflags_sl = []
102 ldflags_mod = []
103
104 test_c_args = []
105
106 os_deps = []
107 backend_both_deps = []
108 backend_deps = []
109 libpq_deps = []
110
111 pg_sysroot = ''
112
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
115
116
117
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
121
122 pg_version = meson.project_version()
123
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']
130 else
131 pg_version_arr = pg_version.split('.')
132 endif
133
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
137
138 pg_url = 'https://www.postgresql.org/'
139
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')
146
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', '')
155
156
157
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
161
162 exesuffix = '' # overridden below where necessary
163 dlsuffix = '.so' # overridden below where necessary
164 library_path_var = 'LD_LIBRARY_PATH'
165
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@'
171
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 = []
175
176 memset_loop_limit = 1024
177
178 # Choice of shared memory and semaphore implementation
179 shmem_kind = 'sysv'
180 sema_kind = 'sysv'
181
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'
191 endif
192
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
196 # that purpose.
197 portname = host_system
198
199 if host_system == 'cygwin'
200 sema_kind = 'unnamed_posix'
201 cppflags += '-D_GNU_SOURCE'
202 dlsuffix = '.dll'
203 mod_link_args_fmt = ['@0@']
204 mod_link_with_name = 'lib@0@.exe.a'
205 mod_link_with_dir = 'libdir'
206
207 elif host_system == 'darwin'
208 dlsuffix = '.dylib'
209 library_path_var = 'DYLD_LIBRARY_PATH'
210
211 export_file_format = 'darwin'
212 export_fmt = '-Wl,-exported_symbols_list,@0@'
213
214 mod_link_args_fmt = ['-bundle_loader', '@0@']
215 mod_link_with_dir = 'bindir'
216 mod_link_with_name = '@0@'
217
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))
221 if pg_sysroot != ''
222 cflags += ['-isysroot', pg_sysroot]
223 ldflags += ['-isysroot', pg_sysroot]
224 endif
225
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'
233 endif
234
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')
239
240 elif host_system == 'freebsd'
241 sema_kind = 'unnamed_posix'
242
243 elif host_system == 'linux'
244 sema_kind = 'unnamed_posix'
245 cppflags += '-D_GNU_SOURCE'
246
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
255 # LDFLAGS.
256 ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
257
258 elif host_system == 'openbsd'
259 # you're ok
260
261 elif host_system == 'sunos'
262 portname = 'solaris'
263 export_fmt = '-Wl,-M@0@'
264 cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
265
266 elif host_system == 'windows'
267 portname = 'win32'
268 exesuffix = '.exe'
269 dlsuffix = '.dll'
270 library_path_var = ''
271
272 export_file_format = 'win'
273 export_file_suffix = 'def'
274 if cc.get_id() == 'msvc'
275 export_fmt = '/DEF:@0@'
276 mod_link_with_name = '@0@.exe.lib'
277 else
278 export_fmt = '@0@'
279 mod_link_with_name = 'lib@0@.exe.a'
280 endif
281 mod_link_args_fmt = ['@0@']
282 mod_link_with_dir = 'libdir'
283
284 shmem_kind = 'win32'
285 sema_kind = 'win32'
286
287 cdata.set('WIN32_STACK_RLIMIT', 4194304)
288 if cc.get_id() == 'msvc'
289 ldflags += '/INCREMENTAL:NO'
290 ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
291 # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
292 else
293 ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
294 # Need to allow multiple definitions, we e.g. want to override getopt.
295 ldflags += '-Wl,--allow-multiple-definition'
296 # Ensure we get MSVC-like linking behavior.
297 ldflags += '-Wl,--disable-auto-import'
298 endif
299
300 os_deps += cc.find_library('ws2_32', required: true)
301 secur32_dep = cc.find_library('secur32', required: true)
302 backend_deps += secur32_dep
303 libpq_deps += secur32_dep
304
305 postgres_inc_d += 'src/include/port/win32'
306 if cc.get_id() == 'msvc'
307 postgres_inc_d += 'src/include/port/win32_msvc'
308 endif
309
310 windows = import('windows')
311
312 else
313 # XXX: Should we add an option to override the host_system as an escape
314 # hatch?
315 error('unknown host system: @0@'.format(host_system))
316 endif
317
318
319
320 ###############################################################
321 # Program paths
322 ###############################################################
323
324 # External programs
325 perl = find_program(get_option('PERL'), required: true, native: true)
326 python = find_program(get_option('PYTHON'), required: true, native: true)
327 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
328 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
329 sed = find_program(get_option('SED'), 'sed', native: true, required: false)
330 prove = find_program(get_option('PROVE'), native: true, required: false)
331 tar = find_program(get_option('TAR'), native: true, required: false)
332 gzip = find_program(get_option('GZIP'), native: true, required: false)
333 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
334 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
335 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
336 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
337 missing = find_program('config/missing', native: true)
338 cp = find_program('cp', required: false, native: true)
339 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
340 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
341
342 bison_flags = []
343 if bison.found()
344 bison_version_c = run_command(bison, '--version', check: true)
345 # bison version string helpfully is something like
346 # >>bison (GNU bison) 3.8.1<<
347 bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
348 if bison_version.version_compare('>=3.0')
349 bison_flags += ['-Wno-deprecated']
350 endif
351 endif
352 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
353 bison_kw = {
354 'output': ['@BASENAME@.c', '@BASENAME@.h'],
355 'command': bison_cmd,
356 }
357
358 flex_flags = []
359 if flex.found()
360 flex_version_c = run_command(flex, '--version', check: true)
361 flex_version = flex_version_c.stdout().split(' ')[1].split('\n')[0]
362 endif
363 flex_wrapper = files('src/tools/pgflex')
364 flex_cmd = [python, flex_wrapper,
365 '--builddir', '@BUILD_ROOT@',
366 '--srcdir', '@SOURCE_ROOT@',
367 '--privatedir', '@PRIVATE_DIR@',
368 '--flex', flex, '--perl', perl,
369 '-i', '@INPUT@', '-o', '@OUTPUT0@',
370 ]
371
372 wget = find_program('wget', required: false, native: true)
373 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
374
375 install_files = files('src/tools/install_files')
376
377
378
379 ###############################################################
380 # Path to meson (for tests etc)
381 ###############################################################
382
383 # NB: this should really be part of meson, see
384 # https://github.com/mesonbuild/meson/issues/8511
385 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
386
387 if meson_binpath_r.stdout() == ''
388 error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
389 meson_binpath_r.returncode(),
390 meson_binpath_r.stdout(),
391 meson_binpath_r.stderr()))
392 endif
393
394 meson_binpath_s = meson_binpath_r.stdout().split('\n')
395 meson_binpath_len = meson_binpath_s.length()
396
397 if meson_binpath_len < 1
398 error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
399 endif
400
401 i = 0
402 meson_impl = ''
403 meson_binpath = ''
404 meson_args = []
405 foreach e : meson_binpath_s
406 if i == 0
407 meson_impl = e
408 elif i == 1
409 meson_binpath = e
410 else
411 meson_args += e
412 endif
413 i += 1
414 endforeach
415
416 if meson_impl not in ['muon', 'meson']
417 error('unknown meson implementation "@0@"'.format(meson_impl))
418 endif
419
420 meson_bin = find_program(meson_binpath, native: true)
421
422
423
424 ###############################################################
425 # Option Handling
426 ###############################################################
427
428 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
429 cdata.set('USE_INJECTION_POINTS', get_option('injection_points') ? 1 : false)
430
431 blocksize = get_option('blocksize').to_int() * 1024
432
433 if get_option('segsize_blocks') != 0
434 if get_option('segsize') != 1
435 warning('both segsize and segsize_blocks specified, segsize_blocks wins')
436 endif
437
438 segsize = get_option('segsize_blocks')
439 else
440 segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
441 endif
442
443 cdata.set('BLCKSZ', blocksize, description:
444 '''Size of a disk block --- this also limits the size of a tuple. You can set
445 it bigger if you need bigger tuples (although TOAST should reduce the need
446 to have large tuples, since fields can be spread across multiple tuples).
447 BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
448 currently 2^15 (32768). This is determined by the 15-bit widths of the
449 lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
450 Changing BLCKSZ requires an initdb.''')
451
452 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
453 cdata.set('RELSEG_SIZE', segsize)
454 cdata.set('DEF_PGPORT', get_option('pgport'))
455 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
456 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
457 if get_option('system_tzdata') != ''
458 cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
459 endif
460
461
462
463 ###############################################################
464 # Directories
465 ###############################################################
466
467 # These are set by the equivalent --xxxdir configure options. We
468 # append "postgresql" to some of them, if the string does not already
469 # contain "pgsql" or "postgres", in order to avoid directory clutter.
470
471 pkg = 'postgresql'
472
473 dir_prefix = get_option('prefix')
474
475 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
476
477 dir_bin = get_option('bindir')
478
479 dir_data = get_option('datadir')
480 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
481 dir_data = dir_data / pkg
482 endif
483
484 dir_sysconf = get_option('sysconfdir')
485 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
486 dir_sysconf = dir_sysconf / pkg
487 endif
488
489 dir_lib = get_option('libdir')
490
491 dir_lib_pkg = dir_lib
492 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
493 dir_lib_pkg = dir_lib_pkg / pkg
494 endif
495
496 dir_pgxs = dir_lib_pkg / 'pgxs'
497
498 dir_include = get_option('includedir')
499
500 dir_include_pkg = dir_include
501 dir_include_pkg_rel = ''
502 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
503 dir_include_pkg = dir_include_pkg / pkg
504 dir_include_pkg_rel = pkg
505 endif
506
507 dir_man = get_option('mandir')
508
509 # FIXME: These used to be separately configurable - worth adding?
510 dir_doc = get_option('datadir') / 'doc'
511 if not (dir_prefix_contains_pg or dir_doc.contains('pgsql') or dir_doc.contains('postgres'))
512 dir_doc = dir_doc / pkg
513 endif
514 dir_doc_html = dir_doc / 'html'
515
516 dir_locale = get_option('localedir')
517
518
519 # Derived values
520 dir_bitcode = dir_lib_pkg / 'bitcode'
521 dir_include_internal = dir_include_pkg / 'internal'
522 dir_include_server = dir_include_pkg / 'server'
523 dir_include_extension = dir_include_server / 'extension'
524 dir_data_extension = dir_data / 'extension'
525 dir_doc_extension = dir_doc / 'extension'
526
527
528
529 ###############################################################
530 # Search paths, preparation for compiler tests
531 #
532 # NB: Arguments added later are not automatically used for subsequent
533 # configuration-time checks (so they are more isolated). If they should be
534 # used, they need to be added to test_c_args as well.
535 ###############################################################
536
537 postgres_inc = [include_directories(postgres_inc_d)]
538 test_lib_d = postgres_lib_d
539 test_c_args = cppflags + cflags
540
541
542
543 ###############################################################
544 # Library: bsd-auth
545 ###############################################################
546
547 bsd_authopt = get_option('bsd_auth')
548 bsd_auth = not_found_dep
549 if cc.check_header('bsd_auth.h', required: bsd_authopt,
550 args: test_c_args, include_directories: postgres_inc)
551 cdata.set('USE_BSD_AUTH', 1)
552 bsd_auth = declare_dependency()
553 endif
554
555
556
557 ###############################################################
558 # Library: bonjour
559 #
560 # For now don't search for DNSServiceRegister in a library - only Apple's
561 # Bonjour implementation, which is always linked, works.
562 ###############################################################
563
564 bonjouropt = get_option('bonjour')
565 bonjour = not_found_dep
566 if cc.check_header('dns_sd.h', required: bonjouropt,
567 args: test_c_args, include_directories: postgres_inc) and \
568 cc.has_function('DNSServiceRegister',
569 args: test_c_args, include_directories: postgres_inc)
570 cdata.set('USE_BONJOUR', 1)
571 bonjour = declare_dependency()
572 endif
573
574
575
576 ###############################################################
577 # Option: docs in HTML and man page format
578 ###############################################################
579
580 docs_opt = get_option('docs')
581 docs_dep = not_found_dep
582 if not docs_opt.disabled()
583 if xmllint_bin.found() and xsltproc_bin.found()
584 docs_dep = declare_dependency()
585 elif docs_opt.enabled()
586 error('missing required tools (xmllint and xsltproc needed) for docs in HTML / man page format')
587 endif
588 endif
589
590
591
592 ###############################################################
593 # Option: docs in PDF format
594 ###############################################################
595
596 docs_pdf_opt = get_option('docs_pdf')
597 docs_pdf_dep = not_found_dep
598 if not docs_pdf_opt.disabled()
599 fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
600 if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
601 docs_pdf_dep = declare_dependency()
602 elif docs_pdf_opt.enabled()
603 error('missing required tools for docs in PDF format')
604 endif
605 endif
606
607
608
609 ###############################################################
610 # Library: GSSAPI
611 ###############################################################
612
613 gssapiopt = get_option('gssapi')
614 krb_srvtab = ''
615 have_gssapi = false
616 if not gssapiopt.disabled()
617 gssapi = dependency('krb5-gssapi', required: gssapiopt)
618 have_gssapi = gssapi.found()
619
620 if not have_gssapi
621 elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
622 args: test_c_args, include_directories: postgres_inc)
623 cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
624 elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
625 cdata.set('HAVE_GSSAPI_H', 1)
626 else
627 have_gssapi = false
628 endif
629
630 if not have_gssapi
631 elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi, required: false,
632 args: test_c_args, include_directories: postgres_inc)
633 cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
634 elif cc.check_header('gssapi_ext.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
635 cdata.set('HAVE_GSSAPI_EXT_H', 1)
636 else
637 have_gssapi = false
638 endif
639
640 if not have_gssapi
641 elif cc.has_function('gss_store_cred_into', dependencies: gssapi,
642 args: test_c_args, include_directories: postgres_inc)
643 cdata.set('ENABLE_GSS', 1)
644
645 krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
646 cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
647 elif gssapiopt.enabled()
648 error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
649 else
650 have_gssapi = false
651 endif
652 endif
653 if not have_gssapi
654 gssapi = not_found_dep
655 endif
656
657
658
659 ###############################################################
660 # Library: ldap
661 ###############################################################
662
663 ldapopt = get_option('ldap')
664 if ldapopt.disabled()
665 ldap = not_found_dep
666 ldap_r = not_found_dep
667 elif host_system == 'windows'
668 ldap = cc.find_library('wldap32', required: ldapopt)
669 ldap_r = ldap
670 else
671 # macos framework dependency is buggy for ldap (one can argue whether it's
672 # Apple's or meson's fault), leading to an endless recursion with ldap.h
673 # including itself. See https://github.com/mesonbuild/meson/issues/10002
674 # Luckily we only need pkg-config support, so the workaround isn't
675 # complicated.
676 ldap = dependency('ldap', method: 'pkg-config', required: false)
677 ldap_r = ldap
678
679 # Before 2.5 openldap didn't have a pkg-config file, and it might not be
680 # installed
681 if not ldap.found()
682 ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
683 has_headers: 'ldap.h', header_include_directories: postgres_inc)
684
685 # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
686 # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
687 # library from a separate OpenLDAP installation). The most reliable
688 # way to check that is to check for a function introduced in 2.5.
689 if not ldap.found()
690 # don't have ldap, we shouldn't check for ldap_r
691 elif cc.has_function('ldap_verify_credentials',
692 dependencies: ldap, args: test_c_args)
693 ldap_r = ldap # ldap >= 2.5, no need for ldap_r
694 else
695
696 # Use ldap_r for FE if available, else assume ldap is thread-safe.
697 ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
698 has_headers: 'ldap.h', header_include_directories: postgres_inc)
699 if not ldap_r.found()
700 ldap_r = ldap
701 else
702 # On some platforms ldap_r fails to link without PTHREAD_LIBS.
703 ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
704 endif
705
706 # PostgreSQL sometimes loads libldap_r and plain libldap into the same
707 # process. Check for OpenLDAP versions known not to tolerate doing so;
708 # assume non-OpenLDAP implementations are safe. The dblink test suite
709 # exercises the hazardous interaction directly.
710 compat_test_code = '''
711 #include <ldap.h>
712 #if !defined(LDAP_VENDOR_VERSION) || \
713 (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
714 LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
715 choke me
716 #endif
717 '''
718 if not cc.compiles(compat_test_code,
719 name: 'LDAP implementation compatible',
720 dependencies: ldap, args: test_c_args)
721 warning('''
722 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
723 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
724 *** also uses LDAP will crash on exit.''')
725 endif
726 endif
727 endif
728
729 if ldap.found() and cc.has_function('ldap_initialize',
730 dependencies: ldap, args: test_c_args)
731 cdata.set('HAVE_LDAP_INITIALIZE', 1)
732 endif
733 endif
734
735 if ldap.found()
736 assert(ldap_r.found())
737 cdata.set('USE_LDAP', 1)
738 else
739 assert(not ldap_r.found())
740 endif
741
742
743
744 ###############################################################
745 # Library: LLVM
746 ###############################################################
747
748 llvmopt = get_option('llvm')
749 llvm = not_found_dep
750 if add_languages('cpp', required: llvmopt, native: false)
751 llvm = dependency('llvm', version: '>=10', method: 'config-tool', required: llvmopt)
752
753 if llvm.found()
754
755 cdata.set('USE_LLVM', 1)
756
757 cpp = meson.get_compiler('cpp')
758
759 llvm_binpath = llvm.get_variable(configtool: 'bindir')
760
761 ccache = find_program('ccache', native: true, required: false)
762 clang = find_program(llvm_binpath / 'clang', required: true)
763 endif
764 elif llvmopt.auto()
765 message('llvm requires a C++ compiler')
766 endif
767
768
769
770 ###############################################################
771 # Library: icu
772 ###############################################################
773
774 icuopt = get_option('icu')
775 if not icuopt.disabled()
776 icu = dependency('icu-uc', required: icuopt)
777 icu_i18n = dependency('icu-i18n', required: icuopt)
778
779 if icu.found()
780 cdata.set('USE_ICU', 1)
781 endif
782
783 else
784 icu = not_found_dep
785 icu_i18n = not_found_dep
786 endif
787
788
789
790 ###############################################################
791 # Library: libxml
792 ###############################################################
793
794 libxmlopt = get_option('libxml')
795 if not libxmlopt.disabled()
796 libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
797
798 if libxml.found()
799 cdata.set('USE_LIBXML', 1)
800 endif
801 else
802 libxml = not_found_dep
803 endif
804
805
806
807 ###############################################################
808 # Library: libxslt
809 ###############################################################
810
811 libxsltopt = get_option('libxslt')
812 if not libxsltopt.disabled()
813 libxslt = dependency('libxslt', required: libxsltopt)
814
815 if libxslt.found()
816 cdata.set('USE_LIBXSLT', 1)
817 endif
818 else
819 libxslt = not_found_dep
820 endif
821
822
823
824 ###############################################################
825 # Library: lz4
826 ###############################################################
827
828 lz4opt = get_option('lz4')
829 if not lz4opt.disabled()
830 lz4 = dependency('liblz4', required: lz4opt)
831
832 if lz4.found()
833 cdata.set('USE_LZ4', 1)
834 cdata.set('HAVE_LIBLZ4', 1)
835 endif
836
837 else
838 lz4 = not_found_dep
839 endif
840
841
842
843 ###############################################################
844 # Library: Tcl (for pltcl)
845 #
846 # NB: tclConfig.sh is used in autoconf build for getting
847 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
848 # variables. For now we have not seen a need to copy
849 # that behaviour to the meson build.
850 ###############################################################
851
852 tclopt = get_option('pltcl')
853 tcl_version = get_option('tcl_version')
854 tcl_dep = not_found_dep
855 if not tclopt.disabled()
856
857 # via pkg-config
858 tcl_dep = dependency(tcl_version, required: false)
859
860 if not tcl_dep.found()
861 tcl_dep = cc.find_library(tcl_version,
862 required: tclopt,
863 dirs: test_lib_d)
864 endif
865
866 if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
867 tcl_dep = not_found_dep
868 endif
869 endif
870
871
872
873 ###############################################################
874 # Library: pam
875 ###############################################################
876
877 pamopt = get_option('pam')
878 if not pamopt.disabled()
879 pam = dependency('pam', required: false)
880
881 if not pam.found()
882 pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
883 endif
884
885 if pam.found()
886 pam_header_found = false
887
888 # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
889 if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
890 args: test_c_args, include_directories: postgres_inc)
891 cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
892 pam_header_found = true
893 elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
894 args: test_c_args, include_directories: postgres_inc)
895 cdata.set('HAVE_PAM_PAM_APPL_H', 1)
896 pam_header_found = true
897 endif
898
899 if pam_header_found
900 cdata.set('USE_PAM', 1)
901 else
902 pam = not_found_dep
903 endif
904 endif
905 else
906 pam = not_found_dep
907 endif
908
909
910
911 ###############################################################
912 # Library: Perl (for plperl)
913 ###############################################################
914
915 perlopt = get_option('plperl')
916 perl_dep = not_found_dep
917 if not perlopt.disabled()
918 perl_may_work = true
919
920 # First verify that perl has the necessary dependencies installed
921 perl_mods = run_command(
922 [perl,
923 '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
924 '-e', ''],
925 check: false)
926 if perl_mods.returncode() != 0
927 perl_may_work = false
928 perl_msg = 'perl installation does not have the required modules'
929 endif
930
931 # Then inquire perl about its configuration
932 if perl_may_work
933 perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
934 perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
935 archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
936 privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
937 useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
938
939 perl_inc_dir = '@0@/CORE'.format(archlibexp)
940
941 if perlversion.version_compare('< 5.14')
942 perl_may_work = false
943 perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
944 elif useshrplib != 'true'
945 perl_may_work = false
946 perl_msg = 'need a shared perl'
947 endif
948 endif
949
950 if perl_may_work
951 # On most platforms, archlibexp is also where the Perl include files live ...
952 perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
953 # ... but on newer macOS versions, we must use -iwithsysroot to look
954 # under sysroot
955 if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
956 fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
957 perl_ccflags = ['-iwithsysroot', perl_inc_dir]
958 endif
959
960 # check compiler finds header
961 if not cc.has_header('perl.h', required: false,
962 args: test_c_args + perl_ccflags, include_directories: postgres_inc)
963 perl_may_work = false
964 perl_msg = 'missing perl.h'
965 endif
966 endif
967
968 if perl_may_work
969 perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
970
971 # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
972 foreach flag : perl_ccflags_r.split(' ')
973 if flag.startswith('-D') and \
974 (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
975 perl_ccflags += flag
976 endif
977 endforeach
978
979 if host_system == 'windows'
980 perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
981
982 if cc.get_id() == 'msvc'
983 # prevent binary mismatch between MSVC built plperl and Strawberry or
984 # msys ucrt perl libraries
985 perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
986 endif
987 endif
988
989 message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
990 message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
991
992 # We are after Embed's ldopts, but without the subset mentioned in
993 # Config's ccdlflags and ldflags. (Those are the choices of those who
994 # built the Perl installation, which are not necessarily appropriate
995 # for building PostgreSQL.)
996 ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
997 undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
998 undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
999
1000 perl_ldopts = []
1001 foreach ldopt : ldopts.split(' ')
1002 if ldopt == '' or ldopt in undesired
1003 continue
1004 endif
1005
1006 perl_ldopts += ldopt.strip('"')
1007 endforeach
1008
1009 message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
1010 message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1011
1012 perl_dep_int = declare_dependency(
1013 compile_args: perl_ccflags,
1014 link_args: perl_ldopts,
1015 version: perlversion,
1016 )
1017
1018 # While we're at it, check that we can link to libperl.
1019 # On most platforms, if perl.h is there then libperl.so will be too, but
1020 # at this writing Debian packages them separately.
1021 perl_link_test = '''
1022 /* see plperl.h */
1023 #ifdef _MSC_VER
1024 #define __inline__ inline
1025 #endif
1026 #include <EXTERN.h>
1027 #include <perl.h>
1028 int main(void)
1029 {
1030 perl_alloc();
1031 }'''
1032 if not cc.links(perl_link_test, name: 'libperl',
1033 args: test_c_args + perl_ccflags + perl_ldopts,
1034 include_directories: postgres_inc)
1035 perl_may_work = false
1036 perl_msg = 'missing libperl'
1037 endif
1038
1039 endif # perl_may_work
1040
1041 if perl_may_work
1042 perl_dep = perl_dep_int
1043 else
1044 if perlopt.enabled()
1045 error('dependency plperl failed: @0@'.format(perl_msg))
1046 else
1047 message('disabling optional dependency plperl: @0@'.format(perl_msg))
1048 endif
1049 endif
1050 endif
1051
1052
1053
1054 ###############################################################
1055 # Library: Python (for plpython)
1056 ###############################################################
1057
1058 pyopt = get_option('plpython')
1059 python3_dep = not_found_dep
1060 if not pyopt.disabled()
1061 pm = import('python')
1062 python3_inst = pm.find_installation(python.path(), required: pyopt)
1063 if python3_inst.found()
1064 python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1065 # Remove this check after we depend on Meson >= 1.1.0
1066 if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt)
1067 python3_dep = not_found_dep
1068 endif
1069 endif
1070 endif
1071
1072
1073
1074 ###############################################################
1075 # Library: Readline
1076 ###############################################################
1077
1078 if not get_option('readline').disabled()
1079 libedit_preferred = get_option('libedit_preferred')
1080 # Set the order of readline dependencies
1081 check_readline_deps = libedit_preferred ? \
1082 ['libedit', 'readline'] : ['readline', 'libedit']
1083
1084 foreach readline_dep : check_readline_deps
1085 readline = dependency(readline_dep, required: false)
1086 if not readline.found()
1087 readline = cc.find_library(readline_dep,
1088 required: get_option('readline'),
1089 dirs: test_lib_d)
1090 endif
1091 if readline.found()
1092 break
1093 endif
1094 endforeach
1095
1096 if readline.found()
1097 cdata.set('HAVE_LIBREADLINE', 1)
1098
1099 editline_prefix = {
1100 'header_prefix': 'editline/',
1101 'flag_prefix': 'EDITLINE_',
1102 }
1103 readline_prefix = {
1104 'header_prefix': 'readline/',
1105 'flag_prefix': 'READLINE_',
1106 }
1107 default_prefix = {
1108 'header_prefix': '',
1109 'flag_prefix': '',
1110 }
1111
1112 # Set the order of prefixes
1113 prefixes = libedit_preferred ? \
1114 [editline_prefix, default_prefix, readline_prefix] : \
1115 [readline_prefix, default_prefix, editline_prefix]
1116
1117 at_least_one_header_found = false
1118 foreach header : ['history', 'readline']
1119 is_found = false
1120 foreach prefix : prefixes
1121 header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1122 # Check history.h and readline.h
1123 if not is_found and cc.has_header(header_file,
1124 args: test_c_args, include_directories: postgres_inc,
1125 dependencies: [readline], required: false)
1126 if header == 'readline'
1127 readline_h = header_file
1128 endif
1129 cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1130 is_found = true
1131 at_least_one_header_found = true
1132 endif
1133 endforeach
1134 endforeach
1135
1136 if not at_least_one_header_found
1137 error('''readline header not found
1138 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1139 failure. It is possible the compiler isn't looking in the proper directory.
1140 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1141 endif
1142
1143 check_funcs = [
1144 'append_history',
1145 'history_truncate_file',
1146 'rl_completion_matches',
1147 'rl_filename_completion_function',
1148 'rl_reset_screen_size',
1149 'rl_variable_bind',
1150 ]
1151
1152 foreach func : check_funcs
1153 found = cc.has_function(func, dependencies: [readline],
1154 args: test_c_args, include_directories: postgres_inc)
1155 cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1156 endforeach
1157
1158 check_vars = [
1159 'rl_completion_suppress_quote',
1160 'rl_filename_quote_characters',
1161 'rl_filename_quoting_function',
1162 ]
1163
1164 foreach var : check_vars
1165 cdata.set('HAVE_' + var.to_upper(),
1166 cc.has_header_symbol(readline_h, var,
1167 args: test_c_args, include_directories: postgres_inc,
1168 prefix: '#include <stdio.h>',
1169 dependencies: [readline]) ? 1 : false)
1170 endforeach
1171
1172 # If found via cc.find_library() ensure headers are found when using the
1173 # dependency. On meson < 0.57 one cannot do compiler checks using the
1174 # dependency returned by declare_dependency(), so we can't do this above.
1175 if readline.type_name() == 'library'
1176 readline = declare_dependency(dependencies: readline,
1177 include_directories: postgres_inc)
1178 endif
1179
1180 # On windows with mingw readline requires auto-import to successfully
1181 # link, as the headers don't use declspec(dllimport)
1182 if host_system == 'windows' and cc.get_id() != 'msvc'
1183 readline = declare_dependency(dependencies: readline,
1184 link_args: '-Wl,--enable-auto-import')
1185 endif
1186 endif
1187
1188 # XXX: Figure out whether to implement mingw warning equivalent
1189 else
1190 readline = not_found_dep
1191 endif
1192
1193
1194
1195 ###############################################################
1196 # Library: selinux
1197 ###############################################################
1198
1199 selinux = not_found_dep
1200 selinuxopt = get_option('selinux')
1201 if meson.version().version_compare('>=0.59')
1202 selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1203 endif
1204 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1205 cdata.set('HAVE_LIBSELINUX',
1206 selinux.found() ? 1 : false)
1207
1208
1209
1210 ###############################################################
1211 # Library: systemd
1212 ###############################################################
1213
1214 systemd = not_found_dep
1215 systemdopt = get_option('systemd')
1216 if meson.version().version_compare('>=0.59')
1217 systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1218 endif
1219 systemd = dependency('libsystemd', required: systemdopt)
1220 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1221
1222
1223
1224 ###############################################################
1225 # Library: SSL
1226 ###############################################################
1227
1228 ssl = not_found_dep
1229 ssl_library = 'none'
1230 sslopt = get_option('ssl')
1231
1232 if sslopt == 'auto' and auto_features.disabled()
1233 sslopt = 'none'
1234 endif
1235
1236 if sslopt in ['auto', 'openssl']
1237 openssl_required = (sslopt == 'openssl')
1238
1239 # Try to find openssl via pkg-config et al, if that doesn't work
1240 # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1241 # the library names that we know about.
1242
1243 # via pkg-config et al
1244 ssl = dependency('openssl', required: false)
1245 # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1246 # we pass cc.find_library() results if necessary
1247 ssl_int = []
1248
1249 # via library + headers
1250 if not ssl.found()
1251 ssl_lib = cc.find_library('ssl',
1252 dirs: test_lib_d,
1253 header_include_directories: postgres_inc,
1254 has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1255 required: openssl_required)
1256 crypto_lib = cc.find_library('crypto',
1257 dirs: test_lib_d,
1258 required: openssl_required)
1259 if ssl_lib.found() and crypto_lib.found()
1260 ssl_int = [ssl_lib, crypto_lib]
1261 ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1262 endif
1263 elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1264 cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1265 ssl_int = [ssl]
1266 else
1267 ssl = not_found_dep
1268 endif
1269
1270 if ssl.found()
1271 check_funcs = [
1272 ['CRYPTO_new_ex_data', {'required': true}],
1273 ['SSL_new', {'required': true}],
1274
1275 # Function introduced in OpenSSL 1.0.2, not in LibreSSL.
1276 ['SSL_CTX_set_cert_cb'],
1277
1278 # Functions introduced in OpenSSL 1.1.0. We used to check for
1279 # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1280 # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1281 # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1282 # functions.
1283 ['OPENSSL_init_ssl'],
1284 ['BIO_meth_new'],
1285 ['ASN1_STRING_get0_data'],
1286 ['HMAC_CTX_new'],
1287 ['HMAC_CTX_free'],
1288
1289 # OpenSSL versions before 1.1.0 required setting callback functions, for
1290 # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1291 # function was removed.
1292 ['CRYPTO_lock'],
1293
1294 # Function introduced in OpenSSL 1.1.1
1295 ['X509_get_signature_info'],
1296 ]
1297
1298 are_openssl_funcs_complete = true
1299 foreach c : check_funcs
1300 func = c.get(0)
1301 val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1302 required = c.get(1, {}).get('required', false)
1303 if required and not val
1304 are_openssl_funcs_complete = false
1305 if openssl_required
1306 error('openssl function @0@ is required'.format(func))
1307 endif
1308 break
1309 elif not required
1310 cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1311 endif
1312 endforeach
1313
1314 if are_openssl_funcs_complete
1315 cdata.set('USE_OPENSSL', 1,
1316 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1317 cdata.set('OPENSSL_API_COMPAT', '0x10002000L',
1318 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1319 ssl_library = 'openssl'
1320 else
1321 ssl = not_found_dep
1322 endif
1323 endif
1324 endif
1325
1326 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1327 error('no SSL library found')
1328 endif
1329
1330
1331
1332 ###############################################################
1333 # Library: uuid
1334 ###############################################################
1335
1336 uuidopt = get_option('uuid')
1337 if uuidopt != 'none'
1338 uuidname = uuidopt.to_upper()
1339 if uuidopt == 'e2fs'
1340 uuid = dependency('uuid', required: true)
1341 uuidfunc = 'uuid_generate'
1342 uuidheader = 'uuid/uuid.h'
1343 elif uuidopt == 'bsd'
1344 # libc should have uuid function
1345 uuid = declare_dependency()
1346 uuidfunc = 'uuid_to_string'
1347 uuidheader = 'uuid.h'
1348 elif uuidopt == 'ossp'
1349 uuid = dependency('ossp-uuid', required: true)
1350 uuidfunc = 'uuid_export'
1351 uuidheader = 'uuid.h'
1352 else
1353 error('unknown uuid build option value: @0@'.format(uuidopt))
1354 endif
1355
1356 if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1357 error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1358 endif
1359 cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1360
1361 cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1362 description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1363 else
1364 uuid = not_found_dep
1365 endif
1366
1367
1368
1369 ###############################################################
1370 # Library: zlib
1371 ###############################################################
1372
1373 zlibopt = get_option('zlib')
1374 zlib = not_found_dep
1375 if not zlibopt.disabled()
1376 zlib_t = dependency('zlib', required: zlibopt)
1377
1378 if zlib_t.type_name() == 'internal'
1379 # if fallback was used, we don't need to test if headers are present (they
1380 # aren't built yet, so we can't test)
1381 zlib = zlib_t
1382 elif not zlib_t.found()
1383 warning('did not find zlib')
1384 elif not cc.has_header('zlib.h',
1385 args: test_c_args, include_directories: postgres_inc,
1386 dependencies: [zlib_t], required: zlibopt)
1387 warning('zlib header not found')
1388 else
1389 zlib = zlib_t
1390 endif
1391
1392 if zlib.found()
1393 cdata.set('HAVE_LIBZ', 1)
1394 endif
1395 endif
1396
1397
1398
1399 ###############################################################
1400 # Library: tap test dependencies
1401 ###############################################################
1402
1403 # Check whether tap tests are enabled or not
1404 tap_tests_enabled = false
1405 tapopt = get_option('tap_tests')
1406 if not tapopt.disabled()
1407 # Checking for perl modules for tap tests
1408 perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1409 if perl_ipc_run_check.returncode() != 0
1410 message(perl_ipc_run_check.stderr().strip())
1411 if tapopt.enabled()
1412 error('Additional Perl modules are required to run TAP tests.')
1413 else
1414 warning('Additional Perl modules are required to run TAP tests.')
1415 endif
1416 else
1417 tap_tests_enabled = true
1418 endif
1419 endif
1420
1421
1422
1423 ###############################################################
1424 # Library: zstd
1425 ###############################################################
1426
1427 zstdopt = get_option('zstd')
1428 if not zstdopt.disabled()
1429 zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
1430
1431 if zstd.found()
1432 cdata.set('USE_ZSTD', 1)
1433 cdata.set('HAVE_LIBZSTD', 1)
1434 endif
1435
1436 else
1437 zstd = not_found_dep
1438 endif
1439
1440
1441
1442 ###############################################################
1443 # Compiler tests
1444 ###############################################################
1445
1446 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1447 # unnecessarily, because we optionally rely on newer features.
1448 c99_test = '''
1449 #include <stdbool.h>
1450 #include <complex.h>
1451 #include <tgmath.h>
1452 #include <inttypes.h>
1453
1454 struct named_init_test {
1455 int a;
1456 int b;
1457 };
1458
1459 extern void structfunc(struct named_init_test);
1460
1461 int main(int argc, char **argv)
1462 {
1463 struct named_init_test nit = {
1464 .a = 3,
1465 .b = 5,
1466 };
1467
1468 for (int loop_var = 0; loop_var < 3; loop_var++)
1469 {
1470 nit.a += nit.b;
1471 }
1472
1473 structfunc((struct named_init_test){1, 0});
1474
1475 return nit.a != 0;
1476 }
1477 '''
1478
1479 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1480 if cc.compiles(c99_test, name: 'c99 with -std=c99',
1481 args: test_c_args + ['-std=c99'])
1482 test_c_args += '-std=c99'
1483 cflags += '-std=c99'
1484 else
1485 error('C compiler does not support C99')
1486 endif
1487 endif
1488
1489 sizeof_long = cc.sizeof('long', args: test_c_args)
1490 cdata.set('SIZEOF_LONG', sizeof_long)
1491 if sizeof_long == 8
1492 cdata.set('HAVE_LONG_INT_64', 1)
1493 pg_int64_type = 'long int'
1494 cdata.set_quoted('INT64_MODIFIER', 'l')
1495 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1496 cdata.set('HAVE_LONG_LONG_INT_64', 1)
1497 pg_int64_type = 'long long int'
1498 cdata.set_quoted('INT64_MODIFIER', 'll')
1499 else
1500 error('do not know how to get a 64bit int')
1501 endif
1502 cdata.set('PG_INT64_TYPE', pg_int64_type)
1503
1504 if host_machine.endian() == 'big'
1505 cdata.set('WORDS_BIGENDIAN', 1)
1506 endif
1507
1508 # Determine memory alignment requirements for the basic C data types.
1509
1510 alignof_types = ['short', 'int', 'long', 'double']
1511 foreach t : alignof_types
1512 align = cc.alignment(t, args: test_c_args)
1513 cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1514 endforeach
1515
1516 # Compute maximum alignment of any basic type.
1517 #
1518 # We require 'double' to have the strictest alignment among the basic types,
1519 # because otherwise the C ABI might impose 8-byte alignment on some of the
1520 # other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
1521 # cause a mismatch between the tuple layout and the C struct layout of a
1522 # catalog tuple. We used to carefully order catalog columns such that any
1523 # fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
1524 # of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
1525 # where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
1526 #
1527 # We assume without checking that int64's alignment is at least as strong
1528 # as long, char, short, or int. Note that we intentionally do not consider
1529 # any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
1530 # would be too much of a penalty for disk and memory space.
1531 alignof_double = cdata.get('ALIGNOF_DOUBLE')
1532 if cc.alignment(pg_int64_type, args: test_c_args) > alignof_double
1533 error('alignment of int64 is greater than the alignment of double')
1534 endif
1535 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
1536
1537 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1538 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1539
1540
1541 # Check if __int128 is a working 128 bit integer type, and if so
1542 # define PG_INT128_TYPE to that typename.
1543 #
1544 # This currently only detects a GCC/clang extension, but support for other
1545 # environments may be added in the future.
1546 #
1547 # For the moment we only test for support for 128bit math; support for
1548 # 128bit literals and snprintf is not required.
1549 if cc.links('''
1550 /*
1551 * We don't actually run this test, just link it to verify that any support
1552 * functions needed for __int128 are present.
1553 *
1554 * These are globals to discourage the compiler from folding all the
1555 * arithmetic tests down to compile-time constants. We do not have
1556 * convenient support for 128bit literals at this point...
1557 */
1558 __int128 a = 48828125;
1559 __int128 b = 97656250;
1560
1561 int main(void)
1562 {
1563 __int128 c,d;
1564 a = (a << 12) + 1; /* 200000000001 */
1565 b = (b << 12) + 5; /* 400000000005 */
1566 /* try the most relevant arithmetic ops */
1567 c = a * b;
1568 d = (c + b) / b;
1569 /* must use the results, else compiler may optimize arithmetic away */
1570 return d != a+1;
1571 }''',
1572 name: '__int128',
1573 args: test_c_args)
1574
1575 buggy_int128 = false
1576
1577 # Use of non-default alignment with __int128 tickles bugs in some compilers.
1578 # If not cross-compiling, we can test for bugs and disable use of __int128
1579 # with buggy compilers. If cross-compiling, hope for the best.
1580 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1581 if not meson.is_cross_build()
1582 r = cc.run('''
1583 /* This must match the corresponding code in c.h: */
1584 #if defined(__GNUC__) || defined(__SUNPRO_C)
1585 #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1586 #elif defined(_MSC_VER)
1587 #define pg_attribute_aligned(a) __declspec(align(a))
1588 #endif
1589 typedef __int128 int128a
1590 #if defined(pg_attribute_aligned)
1591 pg_attribute_aligned(8)
1592 #endif
1593 ;
1594
1595 int128a holder;
1596 void pass_by_val(void *buffer, int128a par) { holder = par; }
1597
1598 int main(void)
1599 {
1600 long int i64 = 97656225L << 12;
1601 int128a q;
1602 pass_by_val(main, (int128a) i64);
1603 q = (int128a) i64;
1604 return q != holder;
1605 }''',
1606 name: '__int128 alignment bug',
1607 args: test_c_args)
1608 assert(r.compiled())
1609 if r.returncode() != 0
1610 buggy_int128 = true
1611 message('__int128 support present but buggy and thus disabled')
1612 endif
1613 endif
1614
1615 if not buggy_int128
1616 cdata.set('PG_INT128_TYPE', '__int128')
1617 cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1618 endif
1619 endif
1620
1621
1622 # Check if the C compiler knows computed gotos (gcc extension, also
1623 # available in at least clang). If so, define HAVE_COMPUTED_GOTO.
1624 #
1625 # Checking whether computed gotos are supported syntax-wise ought to
1626 # be enough, as the syntax is otherwise illegal.
1627 if cc.compiles('''
1628 static inline int foo(void)
1629 {
1630 void *labeladdrs[] = {&&my_label};
1631 goto *labeladdrs[0];
1632 my_label:
1633 return 1;
1634 }''',
1635 args: test_c_args)
1636 cdata.set('HAVE_COMPUTED_GOTO', 1)
1637 endif
1638
1639
1640 # Check if the C compiler understands _Static_assert(),
1641 # and define HAVE__STATIC_ASSERT if so.
1642 #
1643 # We actually check the syntax ({ _Static_assert(...) }), because we need
1644 # gcc-style compound expressions to be able to wrap the thing into macros.
1645 if cc.compiles('''
1646 int main(int arg, char **argv)
1647 {
1648 ({ _Static_assert(1, "foo"); });
1649 }
1650 ''',
1651 args: test_c_args)
1652 cdata.set('HAVE__STATIC_ASSERT', 1)
1653 endif
1654
1655
1656 # We use <stdbool.h> if we have it and it declares type bool as having
1657 # size 1. Otherwise, c.h will fall back to declaring bool as unsigned char.
1658 if cc.has_type('_Bool', args: test_c_args) \
1659 and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1660 and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1661 cdata.set('HAVE__BOOL', 1)
1662 cdata.set('PG_USE_STDBOOL', 1)
1663 endif
1664
1665
1666 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1667 # warning for each use of %m.
1668 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1669 testsrc = '''
1670 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1671 static void call_log(void)
1672 {
1673 emit_log(0, "error: %s: %m", "foo");
1674 }
1675 '''
1676 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1677 foreach a : printf_attributes
1678 if cc.compiles(testsrc.format(a),
1679 args: test_c_args + attrib_error_args, name: 'format ' + a)
1680 cdata.set('PG_PRINTF_ATTRIBUTE', a)
1681 break
1682 endif
1683 endforeach
1684
1685
1686 if cc.has_function_attribute('visibility:default') and \
1687 cc.has_function_attribute('visibility:hidden')
1688 cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1689
1690 # Only newer versions of meson know not to apply gnu_symbol_visibility =
1691 # inlineshidden to C code as well... And either way, we want to put these
1692 # flags into exported files (pgxs, .pc files).
1693 cflags_mod += '-fvisibility=hidden'
1694 cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1695 ldflags_mod += '-fvisibility=hidden'
1696 endif
1697
1698
1699 # Check if various builtins exist. Some builtins are tested separately,
1700 # because we want to test something more complicated than the generic case.
1701 builtins = [
1702 'bswap16',
1703 'bswap32',
1704 'bswap64',
1705 'clz',
1706 'ctz',
1707 'constant_p',
1708 'frame_address',
1709 'popcount',
1710 'unreachable',
1711 ]
1712
1713 foreach builtin : builtins
1714 fname = '__builtin_@0@'.format(builtin)
1715 if cc.has_function(fname, args: test_c_args)
1716 cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1717 endif
1718 endforeach
1719
1720
1721 # Check if the C compiler understands __builtin_types_compatible_p,
1722 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1723 #
1724 # We check usage with __typeof__, though it's unlikely any compiler would
1725 # have the former and not the latter.
1726 if cc.compiles('''
1727 static int x;
1728 static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1729 ''',
1730 name: '__builtin_types_compatible_p',
1731 args: test_c_args)
1732 cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1733 endif
1734
1735
1736 # Check if the C compiler understands __builtin_$op_overflow(),
1737 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1738 #
1739 # Check for the most complicated case, 64 bit multiplication, as a
1740 # proxy for all of the operations. To detect the case where the compiler
1741 # knows the function but library support is missing, we must link not just
1742 # compile, and store the results in global variables so the compiler doesn't
1743 # optimize away the call.
1744 if cc.links('''
1745 INT64 a = 1;
1746 INT64 b = 1;
1747 INT64 result;
1748
1749 int main(void)
1750 {
1751 return __builtin_mul_overflow(a, b, &result);
1752 }''',
1753 name: '__builtin_mul_overflow',
1754 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1755 )
1756 cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1757 endif
1758
1759
1760 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1761 # here. To prevent problems due to two detection methods working, stop
1762 # checking after one.
1763 if cc.links('''
1764 #include <cpuid.h>
1765 int main(int arg, char **argv)
1766 {
1767 unsigned int exx[4] = {0, 0, 0, 0};
1768 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1769 }
1770 ''', name: '__get_cpuid',
1771 args: test_c_args)
1772 cdata.set('HAVE__GET_CPUID', 1)
1773 elif cc.links('''
1774 #include <intrin.h>
1775 int main(int arg, char **argv)
1776 {
1777 unsigned int exx[4] = {0, 0, 0, 0};
1778 __cpuid(exx, 1);
1779 }
1780 ''', name: '__cpuid',
1781 args: test_c_args)
1782 cdata.set('HAVE__CPUID', 1)
1783 endif
1784
1785
1786 # Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
1787 if cc.links('''
1788 #include <cpuid.h>
1789 int main(int arg, char **argv)
1790 {
1791 unsigned int exx[4] = {0, 0, 0, 0};
1792 __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
1793 }
1794 ''', name: '__get_cpuid_count',
1795 args: test_c_args)
1796 cdata.set('HAVE__GET_CPUID_COUNT', 1)
1797 elif cc.links('''
1798 #include <intrin.h>
1799 int main(int arg, char **argv)
1800 {
1801 unsigned int exx[4] = {0, 0, 0, 0};
1802 __cpuidex(exx, 7, 0);
1803 }
1804 ''', name: '__cpuidex',
1805 args: test_c_args)
1806 cdata.set('HAVE__CPUIDEX', 1)
1807 endif
1808
1809
1810 # Defend against clang being used on x86-32 without SSE2 enabled. As current
1811 # versions of clang do not understand -fexcess-precision=standard, the use of
1812 # x87 floating point operations leads to problems like isinf possibly returning
1813 # false for a value that is infinite when converted from the 80bit register to
1814 # the 8byte memory representation.
1815 #
1816 # Only perform the test if the compiler doesn't understand
1817 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1818 # automatically.
1819 if '-fexcess-precision=standard' not in cflags
1820 if not cc.compiles('''
1821 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1822 choke me
1823 #endif''',
1824 name: '', args: test_c_args)
1825 error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1826 endif
1827 endif
1828
1829
1830
1831 ###############################################################
1832 # Compiler flags
1833 ###############################################################
1834
1835 common_functional_flags = [
1836 # Disable strict-aliasing rules; needed for gcc 3.3+
1837 '-fno-strict-aliasing',
1838 # Disable optimizations that assume no overflow; needed for gcc 4.3+
1839 '-fwrapv',
1840 '-fexcess-precision=standard',
1841 ]
1842
1843 cflags += cc.get_supported_arguments(common_functional_flags)
1844 if llvm.found()
1845 cxxflags += cpp.get_supported_arguments(common_functional_flags)
1846 endif
1847
1848 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1849 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1850
1851 common_warning_flags = [
1852 '-Wmissing-prototypes',
1853 '-Wpointer-arith',
1854 # Really don't want VLAs to be used in our dialect of C
1855 '-Werror=vla',
1856 # On macOS, complain about usage of symbols newer than the deployment target
1857 '-Werror=unguarded-availability-new',
1858 '-Wendif-labels',
1859 '-Wmissing-format-attribute',
1860 '-Wimplicit-fallthrough=3',
1861 '-Wcast-function-type',
1862 '-Wshadow=compatible-local',
1863 # This was included in -Wall/-Wformat in older GCC versions
1864 '-Wformat-security',
1865 ]
1866
1867 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1868 if llvm.found()
1869 cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1870 endif
1871
1872 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1873 # the result for them
1874 cflags_no_decl_after_statement = []
1875 if cc.has_argument('-Wdeclaration-after-statement')
1876 cflags_warn += '-Wdeclaration-after-statement'
1877 cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1878 endif
1879
1880
1881 # The following tests want to suppress various unhelpful warnings by adding
1882 # -Wno-foo switches. But gcc won't complain about unrecognized -Wno-foo
1883 # switches, so we have to test for the positive form and if that works,
1884 # add the negative form.
1885
1886 negative_warning_flags = [
1887 # Suppress clang's unhelpful unused-command-line-argument warnings.
1888 'unused-command-line-argument',
1889
1890 # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1891 # of warnings when building plperl because of usages in the Perl headers.
1892 'compound-token-split-by-macro',
1893
1894 # Similarly disable useless truncation warnings from gcc 8+
1895 'format-truncation',
1896 'stringop-truncation',
1897
1898 # Suppress clang 16's strict warnings about function casts
1899 'cast-function-type-strict',
1900
1901 # To make warning_level=2 / -Wextra work, we'd need at least the following
1902 # 'clobbered',
1903 # 'missing-field-initializers',
1904 # 'sign-compare',
1905 # 'unused-parameter',
1906 ]
1907
1908 foreach w : negative_warning_flags
1909 if cc.has_argument('-W' + w)
1910 cflags_warn += '-Wno-' + w
1911 endif
1912 if llvm.found() and cpp.has_argument('-W' + w)
1913 cxxflags_warn += '-Wno-' + w
1914 endif
1915 endforeach
1916
1917
1918 if cc.get_id() == 'msvc'
1919 cflags_warn += [
1920 '/wd4018', # signed/unsigned mismatch
1921 '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
1922 '/wd4273', # inconsistent DLL linkage
1923 '/wd4101', # unreferenced local variable
1924 '/wd4102', # unreferenced label
1925 '/wd4090', # different 'modifier' qualifiers
1926 '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
1927 ]
1928
1929 cppflags += [
1930 '/DWIN32',
1931 '/DWINDOWS',
1932 '/D__WINDOWS__',
1933 '/D__WIN32__',
1934 '/D_CRT_SECURE_NO_DEPRECATE',
1935 '/D_CRT_NONSTDC_NO_DEPRECATE',
1936 ]
1937
1938 # We never need export libraries. As link.exe reports their creation, they
1939 # are unnecessarily noisy. Similarly, we don't need import library for
1940 # modules, we only import them dynamically, and they're also noisy.
1941 ldflags += '/NOEXP'
1942 ldflags_mod += '/NOIMPLIB'
1943 endif
1944
1945
1946
1947 ###############################################################
1948 # Atomics
1949 ###############################################################
1950
1951 if not get_option('spinlocks')
1952 warning('Not using spinlocks will cause poor performance')
1953 else
1954 cdata.set('HAVE_SPINLOCKS', 1)
1955 endif
1956
1957 if not get_option('atomics')
1958 warning('Not using atomics will cause poor performance')
1959 else
1960 # XXX: perhaps we should require some atomics support in this case these
1961 # days?
1962 cdata.set('HAVE_ATOMICS', 1)
1963
1964 atomic_checks = [
1965 {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
1966 'desc': '__sync_lock_test_and_set(char)',
1967 'test': '''
1968 char lock = 0;
1969 __sync_lock_test_and_set(&lock, 1);
1970 __sync_lock_release(&lock);'''},
1971
1972 {'name': 'HAVE_GCC__SYNC_INT32_TAS',
1973 'desc': '__sync_lock_test_and_set(int32)',
1974 'test': '''
1975 int lock = 0;
1976 __sync_lock_test_and_set(&lock, 1);
1977 __sync_lock_release(&lock);'''},
1978
1979 {'name': 'HAVE_GCC__SYNC_INT32_CAS',
1980 'desc': '__sync_val_compare_and_swap(int32)',
1981 'test': '''
1982 int val = 0;
1983 __sync_val_compare_and_swap(&val, 0, 37);'''},
1984
1985 {'name': 'HAVE_GCC__SYNC_INT64_CAS',
1986 'desc': '__sync_val_compare_and_swap(int64)',
1987 'test': '''
1988 INT64 val = 0;
1989 __sync_val_compare_and_swap(&val, 0, 37);'''},
1990
1991 {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
1992 'desc': ' __atomic_compare_exchange_n(int32)',
1993 'test': '''
1994 int val = 0;
1995 int expect = 0;
1996 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
1997
1998 {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
1999 'desc': ' __atomic_compare_exchange_n(int64)',
2000 'test': '''
2001 INT64 val = 0;
2002 INT64 expect = 0;
2003 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2004 ]
2005
2006 foreach check : atomic_checks
2007 test = '''
2008 int main(void)
2009 {
2010 @0@
2011 }'''.format(check['test'])
2012
2013 cdata.set(check['name'],
2014 cc.links(test,
2015 name: check['desc'],
2016 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
2017 )
2018 endforeach
2019
2020 endif
2021
2022
2023 ###############################################################
2024 # Check for the availability of XSAVE intrinsics.
2025 ###############################################################
2026
2027 cflags_xsave = []
2028 if host_cpu == 'x86' or host_cpu == 'x86_64'
2029
2030 prog = '''
2031 #include <immintrin.h>
2032
2033 int main(void)
2034 {
2035 return _xgetbv(0) & 0xe0;
2036 }
2037 '''
2038
2039 if cc.links(prog, name: 'XSAVE intrinsics without -mxsave',
2040 args: test_c_args)
2041 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2042 elif cc.links(prog, name: 'XSAVE intrinsics with -mxsave',
2043 args: test_c_args + ['-mxsave'])
2044 cdata.set('HAVE_XSAVE_INTRINSICS', 1)
2045 cflags_xsave += '-mxsave'
2046 endif
2047
2048 endif
2049
2050
2051 ###############################################################
2052 # Check for the availability of AVX-512 popcount intrinsics.
2053 ###############################################################
2054
2055 cflags_popcnt = []
2056 if host_cpu == 'x86_64'
2057
2058 prog = '''
2059 #include <immintrin.h>
2060
2061 int main(void)
2062 {
2063 const char buf[sizeof(__m512i)];
2064 INT64 popcnt = 0;
2065 __m512i accum = _mm512_setzero_si512();
2066 const __m512i val = _mm512_maskz_loadu_epi8((__mmask64) 0xf0f0f0f0f0f0f0f0, (const __m512i *) buf);
2067 const __m512i cnt = _mm512_popcnt_epi64(val);
2068 accum = _mm512_add_epi64(accum, cnt);
2069 popcnt = _mm512_reduce_add_epi64(accum);
2070 /* return computed value, to prevent the above being optimized away */
2071 return popcnt == 0;
2072 }
2073 '''
2074
2075 if cc.links(prog, name: 'AVX-512 popcount without -mavx512vpopcntdq -mavx512bw',
2076 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))])
2077 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2078 elif cc.links(prog, name: 'AVX-512 popcount with -mavx512vpopcntdq -mavx512bw',
2079 args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))] + ['-mavx512vpopcntdq'] + ['-mavx512bw'])
2080 cdata.set('USE_AVX512_POPCNT_WITH_RUNTIME_CHECK', 1)
2081 cflags_popcnt += ['-mavx512vpopcntdq'] + ['-mavx512bw']
2082 endif
2083
2084 endif
2085
2086
2087 ###############################################################
2088 # Select CRC-32C implementation.
2089 #
2090 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2091 # use the special CRC instructions for calculating CRC-32C. If we're not
2092 # targeting such a processor, but we can nevertheless produce code that uses
2093 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
2094 # implementations and select which one to use at runtime, depending on whether
2095 # SSE 4.2 is supported by the processor we're running on.
2096 #
2097 # Similarly, if we are targeting an ARM processor that has the CRC
2098 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2099 # we're not targeting such a processor, but can nevertheless produce code that
2100 # uses the CRC instructions, compile both, and select at runtime.
2101 ###############################################################
2102
2103 have_optimized_crc = false
2104 cflags_crc = []
2105 if host_cpu == 'x86' or host_cpu == 'x86_64'
2106
2107 if cc.get_id() == 'msvc'
2108 cdata.set('USE_SSE42_CRC32C', false)
2109 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2110 have_optimized_crc = true
2111 else
2112
2113 prog = '''
2114 #include <nmmintrin.h>
2115
2116 int main(void)
2117 {
2118 unsigned int crc = 0;
2119 crc = _mm_crc32_u8(crc, 0);
2120 crc = _mm_crc32_u32(crc, 0);
2121 /* return computed value, to prevent the above being optimized away */
2122 return crc == 0;
2123 }
2124 '''
2125
2126 if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2127 args: test_c_args)
2128 # Use Intel SSE 4.2 unconditionally.
2129 cdata.set('USE_SSE42_CRC32C', 1)
2130 have_optimized_crc = true
2131 elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2132 args: test_c_args + ['-msse4.2'])
2133 # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2134 # the runtime check.
2135 cflags_crc += '-msse4.2'
2136 cdata.set('USE_SSE42_CRC32C', false)
2137 cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2138 have_optimized_crc = true
2139 endif
2140
2141 endif
2142
2143 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2144
2145 prog = '''
2146 #include <arm_acle.h>
2147
2148 int main(void)
2149 {
2150 unsigned int crc = 0;
2151 crc = __crc32cb(crc, 0);
2152 crc = __crc32ch(crc, 0);
2153 crc = __crc32cw(crc, 0);
2154 crc = __crc32cd(crc, 0);
2155
2156 /* return computed value, to prevent the above being optimized away */
2157 return crc == 0;
2158 }
2159 '''
2160
2161 if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2162 args: test_c_args)
2163 # Use ARM CRC Extension unconditionally
2164 cdata.set('USE_ARMV8_CRC32C', 1)
2165 have_optimized_crc = true
2166 elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2167 args: test_c_args + ['-march=armv8-a+crc'])
2168 # Use ARM CRC Extension, with runtime check
2169 cflags_crc += '-march=armv8-a+crc'
2170 cdata.set('USE_ARMV8_CRC32C', false)
2171 cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2172 have_optimized_crc = true
2173 endif
2174
2175 elif host_cpu == 'loongarch64'
2176
2177 prog = '''
2178 int main(void)
2179 {
2180 unsigned int crc = 0;
2181 crc = __builtin_loongarch_crcc_w_b_w(0, crc);
2182 crc = __builtin_loongarch_crcc_w_h_w(0, crc);
2183 crc = __builtin_loongarch_crcc_w_w_w(0, crc);
2184 crc = __builtin_loongarch_crcc_w_d_w(0, crc);
2185
2186 /* return computed value, to prevent the above being optimized away */
2187 return crc == 0;
2188 }
2189 '''
2190
2191 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',
2192 args: test_c_args)
2193 # Use LoongArch CRC instruction unconditionally
2194 cdata.set('USE_LOONGARCH_CRC32C', 1)
2195 have_optimized_crc = true
2196 endif
2197
2198 endif
2199
2200 if not have_optimized_crc
2201 # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2202 # support.
2203 cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2204 endif
2205
2206
2207
2208 ###############################################################
2209 # Other CPU specific stuff
2210 ###############################################################
2211
2212 if host_cpu == 'x86_64'
2213
2214 if cc.compiles('''
2215 void main(void)
2216 {
2217 long long x = 1; long long r;
2218 __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2219 }''',
2220 name: '@0@: popcntq instruction'.format(host_cpu),
2221 args: test_c_args)
2222 cdata.set('HAVE_X86_64_POPCNTQ', 1)
2223 endif
2224
2225 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2226 # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2227 if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2228 if cc.compiles('''
2229 static inline int
2230 addi(int ra, int si)
2231 {
2232 int res = 0;
2233 if (__builtin_constant_p(si))
2234 __asm__ __volatile__(
2235 " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2236 return res;
2237 }
2238 int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2239 ''',
2240 args: test_c_args)
2241 cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2242 endif
2243 endif
2244 endif
2245
2246
2247
2248 ###############################################################
2249 # Library / OS tests
2250 ###############################################################
2251
2252 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2253 # unnecessary checks over and over, particularly on windows.
2254 header_checks = [
2255 'atomic.h',
2256 'copyfile.h',
2257 'crtdefs.h',
2258 'execinfo.h',
2259 'getopt.h',
2260 'ifaddrs.h',
2261 'langinfo.h',
2262 'mbarrier.h',
2263 'stdbool.h',
2264 'strings.h',
2265 'sys/epoll.h',
2266 'sys/event.h',
2267 'sys/personality.h',
2268 'sys/prctl.h',
2269 'sys/procctl.h',
2270 'sys/signalfd.h',
2271 'sys/ucred.h',
2272 'termios.h',
2273 'ucred.h',
2274 ]
2275
2276 foreach header : header_checks
2277 varname = 'HAVE_' + header.underscorify().to_upper()
2278
2279 # Emulate autoconf behaviour of not-found->undef, found->1
2280 found = cc.has_header(header,
2281 include_directories: postgres_inc, args: test_c_args)
2282 cdata.set(varname, found ? 1 : false,
2283 description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2284 endforeach
2285
2286
2287 decl_checks = [
2288 ['F_FULLFSYNC', 'fcntl.h'],
2289 ['fdatasync', 'unistd.h'],
2290 ['posix_fadvise', 'fcntl.h'],
2291 ['strlcat', 'string.h'],
2292 ['strlcpy', 'string.h'],
2293 ['strnlen', 'string.h'],
2294 ]
2295
2296 # Need to check for function declarations for these functions, because
2297 # checking for library symbols wouldn't handle deployment target
2298 # restrictions on macOS
2299 decl_checks += [
2300 ['preadv', 'sys/uio.h'],
2301 ['pwritev', 'sys/uio.h'],
2302 ]
2303
2304 # Check presence of some optional LLVM functions.
2305 if llvm.found()
2306 decl_checks += [
2307 ['LLVMCreateGDBRegistrationListener', 'llvm-c/ExecutionEngine.h'],
2308 ['LLVMCreatePerfJITEventListener', 'llvm-c/ExecutionEngine.h'],
2309 ]
2310 endif
2311
2312 foreach c : decl_checks
2313 func = c.get(0)
2314 header = c.get(1)
2315 args = c.get(2, {})
2316 varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2317
2318 found = cc.has_header_symbol(header, func,
2319 args: test_c_args, include_directories: postgres_inc,
2320 kwargs: args)
2321 cdata.set10(varname, found, description:
2322 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2323 don't.'''.format(func))
2324 endforeach
2325
2326
2327 if cc.has_type('struct option',
2328 args: test_c_args, include_directories: postgres_inc,
2329 prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2330 cdata.set('HAVE_STRUCT_OPTION', 1)
2331 endif
2332
2333
2334 foreach c : ['opterr', 'optreset']
2335 varname = 'HAVE_INT_' + c.underscorify().to_upper()
2336
2337 if cc.links('''
2338 #include <unistd.h>
2339 int main(void)
2340 {
2341 extern int @0@;
2342 @0@ = 1;
2343 }
2344 '''.format(c), name: c, args: test_c_args)
2345 cdata.set(varname, 1)
2346 else
2347 cdata.set(varname, false)
2348 endif
2349 endforeach
2350
2351 if cc.has_type('socklen_t',
2352 args: test_c_args, include_directories: postgres_inc,
2353 prefix: '''
2354 #include <sys/socket.h>''')
2355 cdata.set('HAVE_SOCKLEN_T', 1)
2356 endif
2357
2358 if cc.has_member('struct sockaddr', 'sa_len',
2359 args: test_c_args, include_directories: postgres_inc,
2360 prefix: '''
2361 #include <sys/types.h>
2362 #include <sys/socket.h>''')
2363 cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2364 endif
2365
2366 if cc.has_member('struct tm', 'tm_zone',
2367 args: test_c_args, include_directories: postgres_inc,
2368 prefix: '''
2369 #include <sys/types.h>
2370 #include <time.h>
2371 ''')
2372 cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2373 endif
2374
2375 if cc.compiles('''
2376 #include <time.h>
2377 extern int foo(void);
2378 int foo(void)
2379 {
2380 return timezone / 60;
2381 }
2382 ''',
2383 name: 'global variable `timezone\' exists',
2384 args: test_c_args, include_directories: postgres_inc)
2385 cdata.set('HAVE_INT_TIMEZONE', 1)
2386 else
2387 cdata.set('HAVE_INT_TIMEZONE', false)
2388 endif
2389
2390 if cc.has_type('union semun',
2391 args: test_c_args,
2392 include_directories: postgres_inc,
2393 prefix: '''
2394 #include <sys/types.h>
2395 #include <sys/ipc.h>
2396 #include <sys/sem.h>
2397 ''')
2398 cdata.set('HAVE_UNION_SEMUN', 1)
2399 endif
2400
2401 if cc.compiles('''
2402 #include <string.h>
2403 int main(void)
2404 {
2405 char buf[100];
2406 switch (strerror_r(1, buf, sizeof(buf)))
2407 { case 0: break; default: break; }
2408 }''',
2409 name: 'strerror_r',
2410 args: test_c_args, include_directories: postgres_inc)
2411 cdata.set('STRERROR_R_INT', 1)
2412 else
2413 cdata.set('STRERROR_R_INT', false)
2414 endif
2415
2416 # Find the right header file for the locale_t type. macOS needs xlocale.h;
2417 # standard is locale.h, but glibc <= 2.25 also had an xlocale.h file that
2418 # we should not use so we check the standard header first. MSVC has a
2419 # replacement defined in src/include/port/win32_port.h.
2420 if not cc.has_type('locale_t', prefix: '#include <locale.h>') and \
2421 cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2422 cdata.set('LOCALE_T_IN_XLOCALE', 1)
2423 endif
2424
2425 # Check if the C compiler understands typeof or a variant. Define
2426 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2427 foreach kw : ['typeof', '__typeof__', 'decltype']
2428 if cc.compiles('''
2429 int main(void)
2430 {
2431 int x = 0;
2432 @0@(x) y;
2433 y = x;
2434 return y;
2435 }
2436 '''.format(kw),
2437 name: 'typeof()',
2438 args: test_c_args, include_directories: postgres_inc)
2439
2440 cdata.set('HAVE_TYPEOF', 1)
2441 if kw != 'typeof'
2442 cdata.set('typeof', kw)
2443 endif
2444
2445 break
2446 endif
2447 endforeach
2448
2449
2450 # Try to find a declaration for wcstombs_l(). It might be in stdlib.h
2451 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2452 # xlocale.h. If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2453 wcstombs_l_test = '''
2454 #include <stdlib.h>
2455 #include <locale.h>
2456 @0@
2457
2458 void main(void)
2459 {
2460 #ifndef wcstombs_l
2461 (void) wcstombs_l;
2462 #endif
2463 }
2464 '''
2465 if (not cc.compiles(wcstombs_l_test.format(''),
2466 name: 'wcstombs_l') and
2467 cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2468 name: 'wcstombs_l in xlocale.h'))
2469 cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2470 endif
2471
2472
2473 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2474 # understands, because it conflicts with __declspec(restrict). Therefore we
2475 # define pg_restrict to the appropriate definition, which presumably won't
2476 # conflict.
2477 #
2478 # We assume C99 support, so we don't need to make this conditional.
2479 cdata.set('pg_restrict', '__restrict')
2480
2481
2482 # Most libraries are included only if they demonstrably provide a function we
2483 # need, but libm is an exception: always include it, because there are too
2484 # many compilers that play cute optimization games that will break probes for
2485 # standard functions such as pow().
2486 os_deps += cc.find_library('m', required: false)
2487
2488 rt_dep = cc.find_library('rt', required: false)
2489
2490 dl_dep = cc.find_library('dl', required: false)
2491
2492 util_dep = cc.find_library('util', required: false)
2493
2494 getopt_dep = cc.find_library('getopt', required: false)
2495 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2496 # Check if we want to replace getopt/getopt_long even if provided by the system
2497 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2498 # so always use our version on Windows
2499 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2500 # (i.e., allow '-' as a flag character), so use our version on those platforms
2501 # - We want to use system's getopt_long() only if the system provides struct
2502 # option
2503 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2504 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2505
2506 # Required on BSDs
2507 execinfo_dep = cc.find_library('execinfo', required: false)
2508
2509 if host_system == 'cygwin'
2510 cygipc_dep = cc.find_library('cygipc', required: false)
2511 else
2512 cygipc_dep = not_found_dep
2513 endif
2514
2515 if host_system == 'sunos'
2516 socket_dep = cc.find_library('socket', required: false)
2517 else
2518 socket_dep = not_found_dep
2519 endif
2520
2521 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2522 # unnecessary checks over and over, particularly on windows.
2523 func_checks = [
2524 ['_configthreadlocale', {'skip': host_system != 'windows'}],
2525 ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2526 ['clock_gettime', {'dependencies': [rt_dep], 'define': false}],
2527 ['copyfile'],
2528 ['copy_file_range'],
2529 # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2530 # when enabling asan the dlopen check doesn't notice that -ldl is actually
2531 # required. Just checking for dlsym() ought to suffice.
2532 ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2533 ['explicit_bzero'],
2534 ['getifaddrs'],
2535 ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2536 ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2537 ['getpeereid'],
2538 ['getpeerucred'],
2539 ['inet_aton'],
2540 ['inet_pton'],
2541 ['kqueue'],
2542 ['mbstowcs_l'],
2543 ['memset_s'],
2544 ['mkdtemp'],
2545 ['posix_fadvise'],
2546 ['posix_fallocate'],
2547 ['ppoll'],
2548 ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2549 ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2550 ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2551 ['setproctitle', {'dependencies': [util_dep]}],
2552 ['setproctitle_fast'],
2553 ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2554 ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2555 ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2556 ['socket', {'dependencies': [socket_dep], 'define': false}],
2557 ['strchrnul'],
2558 ['strerror_r', {'dependencies': [thread_dep]}],
2559 ['strlcat'],
2560 ['strlcpy'],
2561 ['strnlen'],
2562 ['strsignal'],
2563 ['sync_file_range'],
2564 ['syncfs'],
2565 ['uselocale'],
2566 ['wcstombs_l'],
2567 ]
2568
2569 func_check_results = {}
2570 foreach c : func_checks
2571 func = c.get(0)
2572 kwargs = c.get(1, {})
2573 deps = kwargs.get('dependencies', [])
2574
2575 if kwargs.get('skip', false)
2576 continue
2577 endif
2578
2579 found = cc.has_function(func, args: test_c_args)
2580
2581 if not found
2582 foreach dep : deps
2583 if not dep.found()
2584 continue
2585 endif
2586 found = cc.has_function(func, args: test_c_args,
2587 dependencies: [dep])
2588 if found
2589 os_deps += dep
2590 break
2591 endif
2592 endforeach
2593 endif
2594
2595 func_check_results += {func: found}
2596
2597 if kwargs.get('define', true)
2598 # Emulate autoconf behaviour of not-found->undef, found->1
2599 cdata.set('HAVE_' + func.underscorify().to_upper(),
2600 found ? 1 : false,
2601 description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2602 endif
2603 endforeach
2604
2605
2606 if cc.has_function('syslog', args: test_c_args) and \
2607 cc.check_header('syslog.h', args: test_c_args)
2608 cdata.set('HAVE_SYSLOG', 1)
2609 endif
2610
2611
2612 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2613 # semaphores
2614 if sema_kind == 'unnamed_posix' and \
2615 not func_check_results.get('sem_init', false)
2616 sema_kind = 'sysv'
2617 endif
2618
2619 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2620 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2621
2622 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2623 cdata.set_quoted('DLSUFFIX', dlsuffix)
2624
2625
2626 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2627 cdata.set_quoted('PG_VERSION_STR',
2628 'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2629 pg_version, host_machine.cpu_family(), host_system,
2630 cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2631 )
2632 )
2633
2634
2635 ###############################################################
2636 # NLS / Gettext
2637 ###############################################################
2638
2639 nlsopt = get_option('nls')
2640 libintl = not_found_dep
2641
2642 if not nlsopt.disabled()
2643 # otherwise there'd be lots of
2644 # "Gettext not found, all translation (po) targets will be ignored."
2645 # warnings if not found.
2646 msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2647
2648 # meson 0.59 has this wrapped in dependency('intl')
2649 if (msgfmt.found() and
2650 cc.check_header('libintl.h', required: nlsopt,
2651 args: test_c_args, include_directories: postgres_inc))
2652
2653 # in libc
2654 if cc.has_function('ngettext')
2655 libintl = declare_dependency()
2656 else
2657 libintl = cc.find_library('intl',
2658 has_headers: ['libintl.h'], required: nlsopt,
2659 header_include_directories: postgres_inc,
2660 dirs: test_lib_d)
2661 endif
2662 endif
2663
2664 if libintl.found()
2665 i18n = import('i18n')
2666 cdata.set('ENABLE_NLS', 1)
2667 endif
2668 endif
2669
2670
2671
2672 ###############################################################
2673 # Build
2674 ###############################################################
2675
2676 # Set up compiler / linker arguments to be used everywhere, individual targets
2677 # can add further args directly, or indirectly via dependencies
2678 add_project_arguments(cflags, language: ['c'])
2679 add_project_arguments(cppflags, language: ['c'])
2680 add_project_arguments(cflags_warn, language: ['c'])
2681 add_project_arguments(cxxflags, language: ['cpp'])
2682 add_project_arguments(cppflags, language: ['cpp'])
2683 add_project_arguments(cxxflags_warn, language: ['cpp'])
2684 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2685
2686
2687 # Collect a number of lists of things while recursing through the source
2688 # tree. Later steps then can use those.
2689
2690 # list of targets for various alias targets
2691 backend_targets = []
2692 bin_targets = []
2693 pl_targets = []
2694 contrib_targets = []
2695 testprep_targets = []
2696 nls_targets = []
2697
2698
2699 # Define the tests to distribute them to the correct test styles later
2700 test_deps = []
2701 tests = []
2702
2703
2704 # Default options for targets
2705
2706 # First identify rpaths
2707 bin_install_rpaths = []
2708 lib_install_rpaths = []
2709 mod_install_rpaths = []
2710
2711
2712 # Don't add rpaths on darwin for now - as long as only absolute references to
2713 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2714 # their final destination.
2715 if host_system != 'darwin'
2716 # Add absolute path to libdir to rpath. This ensures installed binaries /
2717 # libraries find our libraries (mainly libpq).
2718 bin_install_rpaths += dir_prefix / dir_lib
2719 lib_install_rpaths += dir_prefix / dir_lib
2720 mod_install_rpaths += dir_prefix / dir_lib
2721
2722 # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2723 #
2724 # Not needed on darwin even if we use relative rpaths for our own libraries,
2725 # as the install_name of libraries in extra_lib_dirs will point to their
2726 # location anyway.
2727 bin_install_rpaths += postgres_lib_d
2728 lib_install_rpaths += postgres_lib_d
2729 mod_install_rpaths += postgres_lib_d
2730 endif
2731
2732
2733 # Define arguments for default targets
2734
2735 default_target_args = {
2736 'implicit_include_directories': false,
2737 'install': true,
2738 }
2739
2740 default_lib_args = default_target_args + {
2741 'name_prefix': '',
2742 }
2743
2744 internal_lib_args = default_lib_args + {
2745 'build_by_default': false,
2746 'install': false,
2747 }
2748
2749 default_mod_args = default_lib_args + {
2750 'name_prefix': '',
2751 'install_dir': dir_lib_pkg,
2752 }
2753
2754 default_bin_args = default_target_args + {
2755 'install_dir': dir_bin,
2756 }
2757
2758 if get_option('rpath')
2759 default_lib_args += {
2760 'install_rpath': ':'.join(lib_install_rpaths),
2761 }
2762
2763 default_mod_args += {
2764 'install_rpath': ':'.join(mod_install_rpaths),
2765 }
2766
2767 default_bin_args += {
2768 'install_rpath': ':'.join(bin_install_rpaths),
2769 }
2770 endif
2771
2772
2773 # Helper for exporting a limited number of symbols
2774 gen_export_kwargs = {
2775 'input': 'exports.txt',
2776 'output': '@BASENAME@.'+export_file_suffix,
2777 'command': [perl, files('src/tools/gen_export.pl'),
2778 '--format', export_file_format,
2779 '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2780 'build_by_default': false,
2781 'install': false,
2782 }
2783
2784
2785
2786 ###
2787 ### Helpers for custom targets used across the tree
2788 ###
2789
2790 catalog_pm = files('src/backend/catalog/Catalog.pm')
2791 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2792 gen_kwlist_deps = [perfect_hash_pm]
2793 gen_kwlist_cmd = [
2794 perl, '-I', '@SOURCE_ROOT@/src/tools',
2795 files('src/tools/gen_keywordlist.pl'),
2796 '--output', '@OUTDIR@', '@INPUT@']
2797
2798
2799
2800 ###
2801 ### windows resources related stuff
2802 ###
2803
2804 if host_system == 'windows'
2805 pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2806 win32ver_rc = files('src/port/win32ver.rc')
2807 rcgen = find_program('src/tools/rcgen', native: true)
2808
2809 rcgen_base_args = [
2810 '--srcdir', '@SOURCE_DIR@',
2811 '--builddir', meson.build_root(),
2812 '--rcout', '@OUTPUT0@',
2813 '--out', '@OUTPUT1@',
2814 '--input', '@INPUT@',
2815 '@EXTRA_ARGS@',
2816 ]
2817
2818 if cc.get_argument_syntax() == 'msvc'
2819 rc = find_program('rc', required: true)
2820 rcgen_base_args += ['--rc', rc.path()]
2821 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2822 else
2823 windres = find_program('windres', required: true)
2824 rcgen_base_args += ['--windres', windres.path()]
2825 rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2826 endif
2827
2828 # msbuild backend doesn't support this atm
2829 if meson.backend() == 'ninja'
2830 rcgen_base_args += ['--depfile', '@DEPFILE@']
2831 endif
2832
2833 rcgen_bin_args = rcgen_base_args + [
2834 '--VFT_TYPE', 'VFT_APP',
2835 '--FILEENDING', 'exe',
2836 '--ICO', pg_ico
2837 ]
2838
2839 rcgen_lib_args = rcgen_base_args + [
2840 '--VFT_TYPE', 'VFT_DLL',
2841 '--FILEENDING', 'dll',
2842 ]
2843
2844 rc_bin_gen = generator(rcgen,
2845 depfile: '@BASENAME@.d',
2846 arguments: rcgen_bin_args,
2847 output: rcgen_outputs,
2848 )
2849
2850 rc_lib_gen = generator(rcgen,
2851 depfile: '@BASENAME@.d',
2852 arguments: rcgen_lib_args,
2853 output: rcgen_outputs,
2854 )
2855 endif
2856
2857
2858
2859 # headers that the whole build tree depends on
2860 generated_headers = []
2861 # headers that the backend build depends on
2862 generated_backend_headers = []
2863 # configure_files() output, needs a way of converting to file names
2864 configure_files = []
2865
2866 # generated files that might conflict with a partial in-tree autoconf build
2867 generated_sources = []
2868 # same, for paths that differ between autoconf / meson builds
2869 # elements are [dir, [files]]
2870 generated_sources_ac = {}
2871
2872
2873 # First visit src/include - all targets creating headers are defined
2874 # within. That makes it easy to add the necessary dependencies for the
2875 # subsequent build steps.
2876
2877 subdir('src/include')
2878
2879 subdir('config')
2880
2881 # Then through src/port and src/common, as most other things depend on them
2882
2883 frontend_port_code = declare_dependency(
2884 compile_args: ['-DFRONTEND'],
2885 include_directories: [postgres_inc],
2886 dependencies: os_deps,
2887 )
2888
2889 backend_port_code = declare_dependency(
2890 compile_args: ['-DBUILDING_DLL'],
2891 include_directories: [postgres_inc],
2892 sources: [errcodes], # errcodes.h is needed due to use of ereport
2893 dependencies: os_deps,
2894 )
2895
2896 subdir('src/port')
2897
2898 frontend_common_code = declare_dependency(
2899 compile_args: ['-DFRONTEND'],
2900 include_directories: [postgres_inc],
2901 sources: generated_headers,
2902 dependencies: [os_deps, zlib, zstd],
2903 )
2904
2905 backend_common_code = declare_dependency(
2906 compile_args: ['-DBUILDING_DLL'],
2907 include_directories: [postgres_inc],
2908 sources: generated_headers,
2909 dependencies: [os_deps, zlib, zstd],
2910 )
2911
2912 subdir('src/common')
2913
2914 # all shared libraries should depend on shlib_code
2915 shlib_code = declare_dependency(
2916 link_args: ldflags_sl,
2917 )
2918
2919 # all static libraries not part of the backend should depend on this
2920 frontend_stlib_code = declare_dependency(
2921 include_directories: [postgres_inc],
2922 link_with: [common_static, pgport_static],
2923 sources: generated_headers,
2924 dependencies: [os_deps, libintl],
2925 )
2926
2927 # all shared libraries not part of the backend should depend on this
2928 frontend_shlib_code = declare_dependency(
2929 include_directories: [postgres_inc],
2930 link_with: [common_shlib, pgport_shlib],
2931 sources: generated_headers,
2932 dependencies: [shlib_code, os_deps, libintl],
2933 )
2934
2935 # Dependencies both for static and shared libpq
2936 libpq_deps += [
2937 thread_dep,
2938
2939 gssapi,
2940 ldap_r,
2941 libintl,
2942 ssl,
2943 ]
2944
2945 subdir('src/interfaces/libpq')
2946 # fe_utils depends on libpq
2947 subdir('src/fe_utils')
2948
2949 # for frontend binaries
2950 frontend_code = declare_dependency(
2951 include_directories: [postgres_inc],
2952 link_with: [fe_utils, common_static, pgport_static],
2953 sources: generated_headers,
2954 dependencies: [os_deps, libintl],
2955 )
2956
2957 backend_both_deps += [
2958 thread_dep,
2959 bsd_auth,
2960 gssapi,
2961 icu,
2962 icu_i18n,
2963 ldap,
2964 libintl,
2965 libxml,
2966 lz4,
2967 pam,
2968 ssl,
2969 systemd,
2970 zlib,
2971 zstd,
2972 ]
2973
2974 backend_mod_deps = backend_both_deps + os_deps
2975
2976 backend_code = declare_dependency(
2977 compile_args: ['-DBUILDING_DLL'],
2978 include_directories: [postgres_inc],
2979 link_args: ldflags_be,
2980 link_with: [],
2981 sources: generated_headers + generated_backend_headers,
2982 dependencies: os_deps + backend_both_deps + backend_deps,
2983 )
2984
2985 # install these files only during test, not main install
2986 test_install_data = []
2987 test_install_libs = []
2988
2989 # src/backend/meson.build defines backend_mod_code used for extension
2990 # libraries.
2991
2992
2993 # Then through the main sources. That way contrib can have dependencies on
2994 # main sources. Note that this explicitly doesn't enter src/test, right now a
2995 # few regression tests depend on contrib files.
2996
2997 subdir('src')
2998
2999 subdir('contrib')
3000
3001 subdir('src/test')
3002 subdir('src/interfaces/libpq/test')
3003 subdir('src/interfaces/ecpg/test')
3004
3005 subdir('doc/src/sgml')
3006
3007 generated_sources_ac += {'': ['GNUmakefile']}
3008
3009 # After processing src/test, add test_install_libs to the testprep_targets
3010 # to build them
3011 testprep_targets += test_install_libs
3012
3013
3014 # If there are any files in the source directory that we also generate in the
3015 # build directory, they might get preferred over the newly generated files,
3016 # e.g. because of a #include "file", which always will search in the current
3017 # directory first.
3018 message('checking for file conflicts between source and build directory')
3019 conflicting_files = []
3020 potentially_conflicting_files_t = []
3021 potentially_conflicting_files_t += generated_headers
3022 potentially_conflicting_files_t += generated_backend_headers
3023 potentially_conflicting_files_t += generated_backend_sources
3024 potentially_conflicting_files_t += generated_sources
3025
3026 potentially_conflicting_files = []
3027
3028 # convert all sources of potentially conflicting files into uniform shape
3029 foreach t : potentially_conflicting_files_t
3030 potentially_conflicting_files += t.full_path()
3031 endforeach
3032 foreach t1 : configure_files
3033 if meson.version().version_compare('>=0.59')
3034 t = fs.parent(t1) / fs.name(t1)
3035 else
3036 t = '@0@'.format(t1)
3037 endif
3038 potentially_conflicting_files += meson.current_build_dir() / t
3039 endforeach
3040 foreach sub, fnames : generated_sources_ac
3041 sub = meson.build_root() / sub
3042 foreach fname : fnames
3043 potentially_conflicting_files += sub / fname
3044 endforeach
3045 endforeach
3046
3047 # find and report conflicting files
3048 foreach build_path : potentially_conflicting_files
3049 build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3050 # str.replace is in 0.56
3051 src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3052 if fs.exists(src_path) or fs.is_symlink(src_path)
3053 conflicting_files += src_path
3054 endif
3055 endforeach
3056 # XXX: Perhaps we should generate a file that would clean these up? The list
3057 # can be long.
3058 if conflicting_files.length() > 0
3059 errmsg_cleanup = '''
3060 Conflicting files in source directory:
3061 @0@
3062
3063 The conflicting files need to be removed, either by removing the files listed
3064 above, or by running configure and then make maintainer-clean.
3065 '''
3066 errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3067 error(errmsg_nonclean_base.format(errmsg_cleanup))
3068 endif
3069
3070
3071
3072 ###############################################################
3073 # Install targets
3074 ###############################################################
3075
3076
3077 # We want to define additional install targets beyond what meson provides. For
3078 # that we need to define targets depending on nearly everything. We collected
3079 # the results of i18n.gettext() invocations into nls_targets, that also
3080 # includes maintainer targets though. Collect the ones we want as a dependency.
3081 #
3082 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3083 # generation happens during install, so that's not a real issue.
3084 nls_mo_targets = []
3085 if libintl.found() and meson.version().version_compare('>=0.60')
3086 # use range() to avoid the flattening of the list that foreach() would do
3087 foreach off : range(0, nls_targets.length())
3088 # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3089 # -pot target 3) maintainer -pot target
3090 nls_mo_targets += nls_targets[off][0]
3091 endforeach
3092 alias_target('nls', nls_mo_targets)
3093 endif
3094
3095
3096 all_built = [
3097 backend_targets,
3098 bin_targets,
3099 libpq_st,
3100 pl_targets,
3101 contrib_targets,
3102 nls_mo_targets,
3103 testprep_targets,
3104 ecpg_targets,
3105 ]
3106
3107 # Meson's default install target is quite verbose. Provide one that is quiet.
3108 install_quiet = custom_target('install-quiet',
3109 output: 'install-quiet',
3110 build_always_stale: true,
3111 build_by_default: false,
3112 command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3113 depends: all_built,
3114 )
3115
3116 # Target to install files used for tests, which aren't installed by default
3117 install_test_files_args = [
3118 install_files,
3119 '--prefix', dir_prefix,
3120 '--install', contrib_data_dir, test_install_data,
3121 '--install', dir_lib_pkg, test_install_libs,
3122 ]
3123 run_target('install-test-files',
3124 command: [python] + install_test_files_args,
3125 depends: testprep_targets,
3126 )
3127
3128
3129
3130 ###############################################################
3131 # Test prep
3132 ###############################################################
3133
3134 # DESTDIR for the installation we'll run tests in
3135 test_install_destdir = meson.build_root() / 'tmp_install/'
3136
3137 # DESTDIR + prefix appropriately munged
3138 if build_system != 'windows'
3139 # On unixoid systems this is trivial, we just prepend the destdir
3140 assert(dir_prefix.startswith('/')) # enforced by meson
3141 test_install_location = '@0@@1@'.format(test_install_destdir, dir_prefix)
3142 else
3143 # drives, drive-relative paths, etc make this complicated on windows, call
3144 # into a copy of meson's logic for it
3145 command = [
3146 python, '-c',
3147 'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3148 test_install_destdir, dir_prefix]
3149 test_install_location = run_command(command, check: true).stdout().strip()
3150 endif
3151
3152 meson_install_args = meson_args + ['install'] + {
3153 'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3154 'muon': []
3155 }[meson_impl]
3156
3157 # setup tests should be run first,
3158 # so define priority for these
3159 setup_tests_priority = 100
3160 test('tmp_install',
3161 meson_bin, args: meson_install_args ,
3162 env: {'DESTDIR':test_install_destdir},
3163 priority: setup_tests_priority,
3164 timeout: 300,
3165 is_parallel: false,
3166 suite: ['setup'])
3167
3168 test('install_test_files',
3169 python,
3170 args: install_test_files_args + ['--destdir', test_install_destdir],
3171 priority: setup_tests_priority,
3172 is_parallel: false,
3173 suite: ['setup'])
3174
3175 test_result_dir = meson.build_root() / 'testrun'
3176
3177
3178 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3179 # inevitable conflicts from running tests in parallel, hackishly assign
3180 # different ports for different tests.
3181
3182 testport = 40000
3183
3184 test_env = environment()
3185
3186 temp_install_bindir = test_install_location / get_option('bindir')
3187 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3188 test_env.set('PG_REGRESS', pg_regress.full_path())
3189 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3190 test_env.set('INITDB_TEMPLATE', test_initdb_template)
3191
3192 # Test suites that are not safe by default but can be run if selected
3193 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3194 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3195 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3196
3197 # Add the temporary installation to the library search path on platforms where
3198 # that works (everything but windows, basically). On windows everything
3199 # library-like gets installed into bindir, solving that issue.
3200 if library_path_var != ''
3201 test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
3202 endif
3203
3204
3205 # Create (and remove old) initdb template directory. Tests use that, where
3206 # possible, to make it cheaper to run tests.
3207 #
3208 # Use python to remove the old cached initdb, as we cannot rely on a working
3209 # 'rm' binary on windows.
3210 test('initdb_cache',
3211 python,
3212 args: [
3213 '-c', '''
3214 import shutil
3215 import sys
3216 import subprocess
3217
3218 shutil.rmtree(sys.argv[1], ignore_errors=True)
3219 sp = subprocess.run(sys.argv[2:] + [sys.argv[1]])
3220 sys.exit(sp.returncode)
3221 ''',
3222 test_initdb_template,
3223 temp_install_bindir / 'initdb',
3224 '--auth', 'trust', '--no-sync', '--no-instructions', '--lc-messages=C',
3225 '--no-clean'
3226 ],
3227 priority: setup_tests_priority - 1,
3228 timeout: 300,
3229 is_parallel: false,
3230 env: test_env,
3231 suite: ['setup'])
3232
3233
3234
3235 ###############################################################
3236 # Test Generation
3237 ###############################################################
3238
3239 # When using a meson version understanding exclude_suites, define a
3240 # 'tmp_install' test setup (the default) that excludes tests running against a
3241 # pre-existing install and a 'running' setup that conflicts with creation of
3242 # the temporary installation and tap tests (which don't support running
3243 # against a running server).
3244
3245 running_suites = []
3246 install_suites = []
3247 if meson.version().version_compare('>=0.57')
3248 runningcheck = true
3249 else
3250 runningcheck = false
3251 endif
3252
3253 testwrap = files('src/tools/testwrap')
3254
3255 foreach test_dir : tests
3256 testwrap_base = [
3257 testwrap,
3258 '--basedir', meson.build_root(),
3259 '--srcdir', test_dir['sd'],
3260 ]
3261
3262 foreach kind, v : test_dir
3263 if kind in ['sd', 'bd', 'name']
3264 continue
3265 endif
3266
3267 t = test_dir[kind]
3268
3269 if kind in ['regress', 'isolation', 'ecpg']
3270 if kind == 'regress'
3271 runner = pg_regress
3272 fallback_dbname = 'regression_@0@'
3273 elif kind == 'isolation'
3274 runner = pg_isolation_regress
3275 fallback_dbname = 'isolation_regression_@0@'
3276 elif kind == 'ecpg'
3277 runner = pg_regress_ecpg
3278 fallback_dbname = 'ecpg_regression_@0@'
3279 endif
3280
3281 test_group = test_dir['name']
3282 test_group_running = test_dir['name'] + '-running'
3283
3284 test_output = test_result_dir / test_group / kind
3285 test_output_running = test_result_dir / test_group_running/ kind
3286
3287 # Unless specified by the test, choose a non-conflicting database name,
3288 # to avoid conflicts when running against existing server.
3289 dbname = t.get('dbname',
3290 fallback_dbname.format(test_dir['name']))
3291
3292 test_command_base = [
3293 runner.full_path(),
3294 '--inputdir', t.get('inputdir', test_dir['sd']),
3295 '--expecteddir', t.get('expecteddir', test_dir['sd']),
3296 '--bindir', '',
3297 '--dlpath', test_dir['bd'],
3298 '--max-concurrent-tests=20',
3299 '--dbname', dbname,
3300 ] + t.get('regress_args', [])
3301
3302 test_selection = []
3303 if t.has_key('schedule')
3304 test_selection += ['--schedule', t['schedule'],]
3305 endif
3306
3307 if kind == 'isolation'
3308 test_selection += t.get('specs', [])
3309 else
3310 test_selection += t.get('sql', [])
3311 endif
3312
3313 env = test_env
3314 env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3315
3316 test_kwargs = {
3317 'protocol': 'tap',
3318 'priority': 10,
3319 'timeout': 1000,
3320 'depends': test_deps + t.get('deps', []),
3321 'env': env,
3322 } + t.get('test_kwargs', {})
3323
3324 test(test_group / kind,
3325 python,
3326 args: [
3327 testwrap_base,
3328 '--testgroup', test_group,
3329 '--testname', kind,
3330 '--',
3331 test_command_base,
3332 '--outputdir', test_output,
3333 '--temp-instance', test_output / 'tmp_check',
3334 '--port', testport.to_string(),
3335 test_selection,
3336 ],
3337 suite: test_group,
3338 kwargs: test_kwargs,
3339 )
3340 install_suites += test_group
3341
3342 # some tests can't support running against running DB
3343 if runningcheck and t.get('runningcheck', true)
3344 test(test_group_running / kind,
3345 python,
3346 args: [
3347 testwrap_base,
3348 '--testgroup', test_group_running,
3349 '--testname', kind,
3350 '--',
3351 test_command_base,
3352 '--outputdir', test_output_running,
3353 test_selection,
3354 ],
3355 is_parallel: t.get('runningcheck-parallel', true),
3356 suite: test_group_running,
3357 kwargs: test_kwargs,
3358 )
3359 running_suites += test_group_running
3360 endif
3361
3362 testport += 1
3363 elif kind == 'tap'
3364 testwrap_tap = testwrap_base
3365 if not tap_tests_enabled
3366 testwrap_tap += ['--skip', 'TAP tests not enabled']
3367 endif
3368
3369 test_command = [
3370 perl.path(),
3371 '-I', meson.source_root() / 'src/test/perl',
3372 '-I', test_dir['sd'],
3373 ]
3374
3375 # Add temporary install, the build directory for non-installed binaries and
3376 # also test/ for non-installed test binaries built separately.
3377 env = test_env
3378 env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3379
3380 foreach name, value : t.get('env', {})
3381 env.set(name, value)
3382 endforeach
3383
3384 test_group = test_dir['name']
3385 test_kwargs = {
3386 'protocol': 'tap',
3387 'suite': test_group,
3388 'timeout': 1000,
3389 'depends': test_deps + t.get('deps', []),
3390 'env': env,
3391 } + t.get('test_kwargs', {})
3392
3393 foreach onetap : t['tests']
3394 # Make tap test names prettier, remove t/ and .pl
3395 onetap_p = onetap
3396 if onetap_p.startswith('t/')
3397 onetap_p = onetap.split('t/')[1]
3398 endif
3399 if onetap_p.endswith('.pl')
3400 onetap_p = fs.stem(onetap_p)
3401 endif
3402
3403 test(test_dir['name'] / onetap_p,
3404 python,
3405 kwargs: test_kwargs,
3406 args: testwrap_tap + [
3407 '--testgroup', test_dir['name'],
3408 '--testname', onetap_p,
3409 '--', test_command,
3410 test_dir['sd'] / onetap,
3411 ],
3412 )
3413 endforeach
3414 install_suites += test_group
3415 else
3416 error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3417 endif
3418
3419 endforeach # kinds of tests
3420
3421 endforeach # directories with tests
3422
3423 # repeat condition so meson realizes version dependency
3424 if meson.version().version_compare('>=0.57')
3425 add_test_setup('tmp_install',
3426 is_default: true,
3427 exclude_suites: running_suites)
3428 add_test_setup('running',
3429 exclude_suites: ['setup'] + install_suites)
3430 endif
3431
3432
3433
3434 ###############################################################
3435 # Pseudo targets
3436 ###############################################################
3437
3438 alias_target('backend', backend_targets)
3439 alias_target('bin', bin_targets + [libpq_st])
3440 alias_target('pl', pl_targets)
3441 alias_target('contrib', contrib_targets)
3442 alias_target('testprep', testprep_targets)
3443
3444 alias_target('world', all_built, docs)
3445 alias_target('install-world', install_quiet, installdocs)
3446
3447 run_target('help',
3448 command: [
3449 perl, '-ne', 'next if /^#/; print',
3450 files('doc/src/sgml/targets-meson.txt'),
3451 ]
3452 )
3453
3454
3455
3456 ###############################################################
3457 # Distribution archive
3458 ###############################################################
3459
3460 # Meson has its own distribution building command (meson dist), but we
3461 # are not using that at this point. The main problem is that, the way
3462 # they have implemented it, it is not deterministic. Also, we want it
3463 # to be equivalent to the "make" version for the time being. But the
3464 # target name "dist" in meson is reserved for that reason, so we call
3465 # the custom target "pgdist".
3466
3467 git = find_program('git', required: false, native: true, disabler: true)
3468 bzip2 = find_program('bzip2', required: false, native: true)
3469
3470 distdir = meson.project_name() + '-' + meson.project_version()
3471
3472 # Note: core.autocrlf=false is needed to avoid line-ending conversion
3473 # in case the environment has a different setting. Without this, a
3474 # tarball created on Windows might be different than on, and unusable
3475 # on, Unix machines.
3476
3477 tar_gz = custom_target('tar.gz',
3478 build_always_stale: true,
3479 command: [git, '-C', '@SOURCE_ROOT@',
3480 '-c', 'core.autocrlf=false',
3481 'archive',
3482 '--format', 'tar.gz',
3483 '-9',
3484 '--prefix', distdir + '/',
3485 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3486 'HEAD', '.'],
3487 output: distdir + '.tar.gz',
3488 )
3489
3490 if bzip2.found()
3491 tar_bz2 = custom_target('tar.bz2',
3492 build_always_stale: true,
3493 command: [git, '-C', '@SOURCE_ROOT@',
3494 '-c', 'core.autocrlf=false',
3495 '-c', 'tar.tar.bz2.command="@0@" -c'.format(bzip2.path()),
3496 'archive',
3497 '--format', 'tar.bz2',
3498 '--prefix', distdir + '/',
3499 '-o', join_paths(meson.build_root(), '@OUTPUT@'),
3500 'HEAD', '.'],
3501 output: distdir + '.tar.bz2',
3502 )
3503 else
3504 tar_bz2 = custom_target('tar.bz2',
3505 command: [perl, '-e', 'exit 1'],
3506 output: distdir + '.tar.bz2',
3507 )
3508 endif
3509
3510 alias_target('pgdist', [tar_gz, tar_bz2])
3511
3512 # Make the standard "dist" command fail, to prevent accidental use.
3513 # But not if we are in a subproject, in case the parent project wants to
3514 # create a dist using the standard Meson command.
3515 if not meson.is_subproject()
3516 # We can only pass the identifier perl here when we depend on >= 0.55
3517 if meson.version().version_compare('>=0.55')
3518 meson.add_dist_script(perl, '-e', 'exit 1')
3519 endif
3520 endif
3521
3522
3523
3524 ###############################################################
3525 # The End, The End, My Friend
3526 ###############################################################
3527
3528 if meson.version().version_compare('>=0.57')
3529
3530 summary(
3531 {
3532 'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3533 'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3534 'segment size': get_option('segsize_blocks') != 0 ?
3535 '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3536 '@0@ GB'.format(get_option('segsize')),
3537 },
3538 section: 'Data layout',
3539 )
3540
3541 summary(
3542 {
3543 'host system': '@0@ @1@'.format(host_system, host_cpu),
3544 'build system': '@0@ @1@'.format(build_machine.system(),
3545 build_machine.cpu_family()),
3546 },
3547 section: 'System',
3548 )
3549
3550 summary(
3551 {
3552 'linker': '@0@'.format(cc.get_linker_id()),
3553 'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3554 },
3555 section: 'Compiler',
3556 )
3557
3558 summary(
3559 {
3560 'CPP FLAGS': ' '.join(cppflags),
3561 'C FLAGS, functional': ' '.join(cflags),
3562 'C FLAGS, warnings': ' '.join(cflags_warn),
3563 'C FLAGS, modules': ' '.join(cflags_mod),
3564 'C FLAGS, user specified': ' '.join(get_option('c_args')),
3565 'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3566 },
3567 section: 'Compiler Flags',
3568 )
3569
3570 if llvm.found()
3571 summary(
3572 {
3573 'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3574 },
3575 section: 'Compiler',
3576 )
3577
3578 summary(
3579 {
3580 'C++ FLAGS, functional': ' '.join(cxxflags),
3581 'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3582 'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3583 },
3584 section: 'Compiler Flags',
3585 )
3586 endif
3587
3588 summary(
3589 {
3590 'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3591 'dtrace': dtrace,
3592 'flex': '@0@ @1@'.format(flex.full_path(), flex_version),
3593 },
3594 section: 'Programs',
3595 )
3596
3597 summary(
3598 {
3599 'bonjour': bonjour,
3600 'bsd_auth': bsd_auth,
3601 'docs': docs_dep,
3602 'docs_pdf': docs_pdf_dep,
3603 'gss': gssapi,
3604 'icu': icu,
3605 'ldap': ldap,
3606 'libxml': libxml,
3607 'libxslt': libxslt,
3608 'llvm': llvm,
3609 'lz4': lz4,
3610 'nls': libintl,
3611 'openssl': ssl,
3612 'pam': pam,
3613 'plperl': perl_dep,
3614 'plpython': python3_dep,
3615 'pltcl': tcl_dep,
3616 'readline': readline,
3617 'selinux': selinux,
3618 'systemd': systemd,
3619 'uuid': uuid,
3620 'zlib': zlib,
3621 'zstd': zstd,
3622 },
3623 section: 'External libraries',
3624 )
3625
3626 endif