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