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