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