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