You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-10-23 21:28:56 +03:00
The build tool in src/build becomes build/build.py with its library in build/lib, and the C part of the documentation tool in doc/src becomes doc/doc.py with its library in doc/lib. They migrate together because doc/src was built on src/build, linking its config and help parsing along with its extensions to the core types. doc.pl runs doc.py rather than building and running a C binary, and meson runs build.py for the code it generates as it builds. The three libraries form the hierarchy the C include path did: build/lib is the base, doc/lib sits on it, and test/lib sits on both. They are implicit namespace packages so a package spans them, and a module lives in exactly one library and holds the union of what the tools need from it, since Python resolves a module name to a single file and cannot extend one the way the C included a core module and added to it. define.yaml declares which libraries each tool may import and the test runner puts only those on the path, so a test of the build library cannot reach the doc or test library any more than the build tool can. The declarations move with the code. config.yaml, error.yaml, and postgres.yaml are now at the root of build, and help.xml becomes doc/xml/reference.xml since it is documentation that the help happens to be generated from, so the generator is told where it is rather than knowing. dist.sh moves to build as well. The documentation tool's own option declarations are gone because they existed only to generate the option parser for the C binary and doc.py parses its command line directly. Three modules in src/build/common were never build tool code. exec, regExp, and string extend the core types for the test harness and the unit tests, which were their only users, so they move to test/src/harness. The json and xml extensions had no users outside the two tools and are removed with them, and the tests for both are trimmed to the core functions that remain. The help unit test built its fixture by calling the generator's C functions directly, which was the last thing outside the tools that depended on them. It now runs build.py help-data to write the packed help and loads that, so it still runs against the current declarations without needing the generated C, which may not have been written when the test runs. The manual page wrapping is a port of the wrapper the binary uses for its own help, so the manual page and pgbackrest help break lines the same way, including where a word longer than a line is left unbroken. libyaml is no longer needed to build pgBackRest since the only thing that read yaml was the C generator. It is dropped from the development container and from every CI platform, and meson no longer looks for it. Code generation needs nothing compiled first either, so a test run no longer builds a generator before it can select the tests. The common source list is merged into the pgbackrest source list since it existed only so the generator could be built from the same files, and the entries that were out of alphabetical order are put in order while the list is being rewritten anyway. Every file the generator writes is byte identical to what the C wrote, for the project declarations and for the documentation's own. The documentation is checked the same way: the HTML rendered on this branch is byte identical to the HTML rendered on integration, every file of it, which exercises the whole pipeline on the real content rather than only the four files the tool writes. Every module in both libraries is declared in define.yaml and has full line and branch coverage. The coverage list is keyed by file rather than by module name, since the same name in two languages is two files and one of them would have silently lost its requirement while both existed. TestError becomes ToolError, since it is the error type for three tools now rather than for the harness alone.
290 lines
12 KiB
Meson
290 lines
12 KiB
Meson
####################################################################################################################################
|
|
# pgBackRest Project
|
|
####################################################################################################################################
|
|
project(
|
|
'pgbackrest',
|
|
['c'],
|
|
version: '2.60.0dev',
|
|
license: 'MIT',
|
|
meson_version: '>=0.55.3',
|
|
default_options: [
|
|
# Core options
|
|
'buildtype=release',
|
|
'warning_level=2',
|
|
|
|
# Base options
|
|
'b_ndebug=if-release',
|
|
|
|
# Perform unity builds in a single file
|
|
'unity_size=100000',
|
|
|
|
# Compiler options
|
|
'c_std=c11',
|
|
],
|
|
)
|
|
|
|
# Selected C compiler
|
|
cc = meson.get_compiler('c')
|
|
|
|
####################################################################################################################################
|
|
# Check for C11 compiler support (setting c_std has no effect -- works in 1.8.1 so likely a bug in our version)
|
|
####################################################################################################################################
|
|
c11_test = '''
|
|
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
|
|
# error "C compiler does not advertise C11 conformance"
|
|
#endif
|
|
'''
|
|
|
|
if not cc.compiles(c11_test)
|
|
if cc.compiles(c11_test, args: '-std=c11')
|
|
add_project_arguments('-std=c11', language: 'c')
|
|
else
|
|
error('C compiler does not support C11')
|
|
endif
|
|
endif
|
|
|
|
####################################################################################################################################
|
|
# OS-specific settings
|
|
####################################################################################################################################
|
|
if host_machine.system() == 'linux'
|
|
add_global_arguments('-D_POSIX_C_SOURCE=200809L', language: 'c')
|
|
elif host_machine.system() == 'darwin'
|
|
add_global_arguments('-D_DARWIN_C_SOURCE', language: 'c')
|
|
endif
|
|
|
|
####################################################################################################################################
|
|
# Enable/disable warnings
|
|
####################################################################################################################################
|
|
# Enable as many additional warnings as possible to catch potential errors
|
|
warning_enable = [
|
|
# Warn whenever a pointer is cast so as to remove a type qualifier from the target type
|
|
'-Wcast-qual',
|
|
|
|
# Warn for implicit conversions that may alter a value
|
|
'-Wconversion',
|
|
|
|
# Warn about duplicated conditions in an if-else-if chain
|
|
'-Wduplicated-cond',
|
|
|
|
# Warn when an if-else has identical branches
|
|
'-Wduplicated-branches',
|
|
|
|
# Warn if floating-point values are used in equality comparisons
|
|
'-Wfloat-equal',
|
|
|
|
# Enable -Wformat plus -Wnonnull, -Wformat-nonliteral, -Wformat-security, and -Wformat-y2k
|
|
'-Wformat=2',
|
|
|
|
# Warn about calls to formatted input/output functions such as sprintf and vsprintf that might overflow the destination buffer
|
|
'-Wformat-overflow=2',
|
|
|
|
# Warn if the format string requires an unsigned argument and the argument is signed and vice versa
|
|
'-Wformat-signedness',
|
|
|
|
# Warn about uninitialized variables which are initialized with themselves
|
|
'-Winit-self',
|
|
|
|
# Warn if a global function is defined without a previous prototype declaration
|
|
'-Wmissing-prototypes',
|
|
|
|
# Warn if a global variable is defined without a previous declaration
|
|
'-Wmissing-variable-declarations',
|
|
|
|
# Warn about anything that depends on the "size of" a function type or of void
|
|
'-Wpointer-arith',
|
|
|
|
# Warn if anything is declared more than once in the same scope, even when the extra declaration is valid and changes nothing
|
|
'-Wredundant-decls',
|
|
|
|
# Warn if a function is declared or defined without specifying the argument types
|
|
'-Wstrict-prototypes',
|
|
|
|
# Warn if a variable-length array is used
|
|
'-Wvla',
|
|
|
|
# Give string constants the type const char[length] so that copying the address of one into a non-const char * pointer produces
|
|
# a warning
|
|
'-Wwrite-strings',
|
|
]
|
|
|
|
# Disable various unhelpful warnings
|
|
warning_disable = [
|
|
# Warn for variables that might be changed by longjmp or vfork. Disable because of constant false positives/negatives.
|
|
'-Wno-clobbered',
|
|
|
|
# Warn if a structure's initializer has some fields missing. Disable so we can initialize with {0}.
|
|
'-Wno-missing-field-initializers',
|
|
]
|
|
|
|
add_project_arguments(cc.get_supported_arguments(warning_enable, warning_disable), language: 'c')
|
|
|
|
####################################################################################################################################
|
|
# Enable additional optimizations for appropriate levels
|
|
####################################################################################################################################
|
|
if get_option('optimization') in ['2', '3']
|
|
optimization_enable = [
|
|
# Unroll loops whose number of iterations can be determined at compile time or upon entry to the loop
|
|
'-funroll-loops',
|
|
|
|
# Perform loop vectorization on trees
|
|
'-ftree-vectorize',
|
|
]
|
|
|
|
add_project_arguments(cc.get_supported_arguments(optimization_enable), language: 'c')
|
|
endif
|
|
|
|
####################################################################################################################################
|
|
# Stop after the first error when error on warn enabled. Subsequent errors are often caused by the first error.
|
|
####################################################################################################################################
|
|
if get_option('fatal-errors')
|
|
add_project_arguments(cc.get_supported_arguments('-Wfatal-errors'), language: 'c')
|
|
endif
|
|
|
|
####################################################################################################################################
|
|
# Generate -fmacro-prefix-map so the relative path to the source directory is not included in the __FILE__ macro. This provides
|
|
# reproducible builds and minimizes the file path in debug messages, just like an in-tree make build. For test source, prefix with
|
|
# test/ in case there are any module name collisions.
|
|
####################################################################################################################################
|
|
python = import('python').find_installation()
|
|
|
|
file_prefix = run_command(
|
|
[
|
|
python,
|
|
'-c',
|
|
'import sys, os; print(os.path.relpath(sys.argv[1], sys.argv[2]))',
|
|
meson.current_source_dir(),
|
|
meson.current_build_dir(),
|
|
],
|
|
check: true,
|
|
).stdout().strip()
|
|
|
|
add_project_arguments(cc.get_supported_arguments('-fmacro-prefix-map=@0@/src/=' . format(file_prefix)), language: 'c')
|
|
add_project_arguments(cc.get_supported_arguments('-fmacro-prefix-map=@0@/test/src/=test/' . format(file_prefix)), language: 'c')
|
|
|
|
####################################################################################################################################
|
|
# Detect a distribution tarball, which is marked by the dist file written into the tarball root by meson dist. A distribution
|
|
# tarball ships the generated files, so the code generation tooling (build.py, the doc and test tools) is not used. A normal source
|
|
# tree such as a git checkout has no marker and generates the files.
|
|
####################################################################################################################################
|
|
dist = run_command(
|
|
[
|
|
python,
|
|
'-c',
|
|
'import os, sys; sys.exit(0 if os.path.exists(os.path.join(sys.argv[1], "dist")) else 1)',
|
|
meson.current_source_dir(),
|
|
],
|
|
check: false,
|
|
).returncode() == 0
|
|
|
|
####################################################################################################################################
|
|
# Build configuration
|
|
####################################################################################################################################
|
|
configuration = configuration_data()
|
|
|
|
# Ensure the C compiler supports __builtin_clzl()
|
|
if not cc.links('''int main(void) {__builtin_clzl(1);}''')
|
|
error('compiler must support __builtin_clzl()')
|
|
endif
|
|
|
|
# Ensure the C compiler supports __builtin_bswap64()
|
|
if not cc.links('''int main(void) {__builtin_bswap64(1);}''')
|
|
error('compiler must support __builtin_bswap64()')
|
|
endif
|
|
|
|
# Check C compiler support for __builtin_types_compatible_p
|
|
if cc.compiles('''int main(void) {__builtin_types_compatible_p(char *, const char *);}''')
|
|
configuration.set('HAVE_BUILTIN_TYPES_COMPATIBLE_P', true, description: 'Is __builtin_types_compatible_p present?')
|
|
endif
|
|
|
|
# Find optional backtrace library
|
|
lib_backtrace = cc.find_library('backtrace', required: false)
|
|
|
|
if lib_backtrace.found()
|
|
configuration.set('HAVE_LIBBACKTRACE', true, description: 'Is libbacktrace present?')
|
|
endif
|
|
|
|
# Find required bz2 library
|
|
lib_bz2 = cc.find_library('bz2')
|
|
|
|
# Find required lz4 library
|
|
lib_lz4 = dependency('liblz4')
|
|
|
|
# Find required openssl library
|
|
lib_openssl = dependency('openssl', version : '>=1.1.1')
|
|
|
|
# Find required pq library
|
|
lib_pq = dependency('libpq')
|
|
|
|
# Find required xml library
|
|
lib_xml = dependency('libxml-2.0')
|
|
|
|
# Find required gz library
|
|
lib_z = dependency('zlib')
|
|
|
|
configuration.set('ZLIB_CONST', true, description: 'Require zlib const input buffer')
|
|
|
|
# Find optional systemd library
|
|
lib_systemd = dependency('libsystemd', required: get_option('libsystemd'))
|
|
|
|
if lib_systemd.found()
|
|
configuration.set('HAVE_LIBSYSTEMD', true, description: 'Is libsystemd present?')
|
|
endif
|
|
|
|
# Find optional libssh2 library
|
|
lib_ssh2 = dependency('libssh2', required: get_option('libssh2'))
|
|
|
|
if lib_ssh2.found()
|
|
configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?')
|
|
endif
|
|
|
|
# Find optional zstd library
|
|
lib_zstd = dependency('libzstd', version: '>=1.0', required: get_option('libzstd'))
|
|
|
|
if lib_zstd.found()
|
|
configuration.set('HAVE_LIBZST', true, description: 'Is libzstd present?')
|
|
endif
|
|
|
|
# Suppress -Wsign-conversion for C libraries (e.g. musl) that do no accept int without warning for FD_*() macros
|
|
if not cc.compiles(
|
|
'''#include <sys/select.h>
|
|
int main(void) {int fd = 1; fd_set s; FD_ZERO(&s); FD_SET(fd, &s); FD_ISSET(fd, &s);}''',
|
|
args: ['-Wsign-conversion', '-Werror'])
|
|
message('Disabling -Wsign-conversion because int is not accepted without warning by FD_*() macros')
|
|
add_project_arguments(cc.get_supported_arguments('-Wno-sign-conversion'), language: 'c')
|
|
endif
|
|
|
|
# Enable debug code
|
|
if get_option('debug')
|
|
configuration.set('DEBUG', true, description: 'Enable debug code')
|
|
endif
|
|
|
|
# Set configuration path
|
|
configuration.set_quoted('CFGOPTDEF_CONFIG_PATH', get_option('configdir'), description: 'Configuration path')
|
|
|
|
# Set VR_NON_STRING macro
|
|
if cc.compiles(
|
|
'''int main(void) {__attribute__((nonstring)) static char test[3] = "ABC";}''',
|
|
args: ['-Wattributes', '-Werror'])
|
|
configuration.set(
|
|
'VR_NON_STRING', '__attribute__((nonstring))',
|
|
description: 'Indicate that the char array is intentionally not NULL terminated')
|
|
else
|
|
configuration.set(
|
|
'VR_NON_STRING', '', description: 'Indicate that the char array is intentionally not NULL terminated')
|
|
endif
|
|
|
|
####################################################################################################################################
|
|
# Include subdirs
|
|
####################################################################################################################################
|
|
subdir('src')
|
|
|
|
# The smoke test is shipped in the distribution so packagers can verify a build. It is in a subdir because unit test builds comment
|
|
# out all subdirs, which excludes the smoke test from them.
|
|
subdir('test')
|
|
|
|
# A distribution tarball ships the generated files, so it neither generates them nor bakes them in
|
|
if not dist
|
|
# Bake the generated files and the dist marker into the tarball so it builds without the code generation tooling
|
|
meson.add_dist_script('build/dist.sh')
|
|
endif
|