]> git.proxmox.com Git - mirror_lxc.git/blobdiff - meson.build
Merge pull request #4287 from hallyn/2023-03-10/dbus
[mirror_lxc.git] / meson.build
index 0550f0cd83991af4b4fa14b39cc8994be6d619ad..cb6f17fa4c58791982df138e5d5984336868cd37 100644 (file)
@@ -4,13 +4,13 @@
 project(
     'lxc',
     'c',
-    version: '4.0.0-devel',
+    version: '5.0.0',
     license: 'LGPLv2+',
     default_options: [
         'b_lto=true',
         'b_lto_mode=thin',
         'b_colorout=always',
-        'b_asneeded=true',
+        'b_asneeded=false',
         'b_pie=true',
         'b_staticpic=true',
         'c_std=gnu11',
@@ -22,12 +22,16 @@ cc = meson.get_compiler('c')
 pkgconfig = import('pkgconfig')
 pkgconfig_libs = []
 
+liblxc_dependencies = []
+oss_fuzz_dependencies = []
+
 # Version.
 liblxc_version = '1.7.0'
 version_data = configuration_data()
-version_data.set('LXC_VERSION_MAJOR', '4')
+version_data.set('LXC_VERSION_MAJOR', '5')
 version_data.set('LXC_VERSION_MINOR', '0')
 version_data.set('LXC_VERSION_MICRO', '0')
+version_data.set('LXC_VERSION_BETA', '')
 version_data.set('LXC_ABI', liblxc_version)
 version_data.set('LXC_DEVEL', '1')
 version_data.set('LXC_VERSION', meson.project_version())
@@ -84,6 +88,11 @@ srcconf = configuration_data()
 srcconf.set('_GNU_SOURCE', true)
 srcconf.set('_FILE_OFFSET_BITS', 64)
 srcconf.set('__STDC_FORMAT_MACROS', true)
+
+## This is a hack to prevent any inclusion ofr linux/mount.h which causes
+## conflicts with sys/mount.h all over the place
+srcconf.set('_LINUX_MOUNT_H', true)
+
 srcconf.set_quoted('APPARMOR_CACHE_DIR', lxcapparmorcachedir)
 srcconf.set_quoted('LIBEXECDIR', libexecdir)
 srcconf.set_quoted('LOGPATH', lxclogpath)
@@ -116,31 +125,62 @@ conf.set('SYSCONFDIR', sysconfdir)
 
 # Set sysconfdir
 fs = import('fs')
-if fs.is_dir('/etc/sysconfig')
+distrosysconfdir = get_option('distrosysconfdir')
+if distrosysconfdir != ''
+    distrosysconfdir = join_paths(sysconfdir, distrosysconfdir)
+    conf.set('LXC_DISTRO_SYSCONF', distrosysconfdir)
+elif fs.is_dir('/etc/sysconfig')
     distrosysconfdir = join_paths(sysconfdir, 'sysconfig')
     conf.set('LXC_DISTRO_SYSCONF', distrosysconfdir)
 elif fs.is_dir('/etc/default')
     distrosysconfdir = join_paths(sysconfdir, 'default')
     conf.set('LXC_DISTRO_SYSCONF', distrosysconfdir)
 else
-    distrosysconfdir = ''
+    error('"distrosysconfdir" is not set')
 endif
 
+# Cross-compile on Android.
+srcconf.set10('IS_BIONIC', host_machine.system() == 'android')
+
 # Custom configuration.
 cgrouppattern = get_option('cgroup-pattern')
+coverity = get_option('coverity-build')
 init_script = get_option('init-script')
+sanitize = get_option('b_sanitize')
 want_examples = get_option('examples')
 want_io_uring = get_option('io-uring-event-loop')
 want_pam_cgroup = get_option('pam-cgroup')
 want_mans = get_option('man')
 want_tests = get_option('tests')
 want_tools = get_option('tools')
+want_tools_multicall = get_option('tools-multicall')
+want_commands = get_option('commands')
+want_capabilities = get_option('capabilities')
+want_apparmor = get_option('apparmor')
+want_openssl = get_option('openssl')
+want_selinux = get_option('selinux')
+want_oss_fuzz = get_option('oss-fuzz')
+want_seccomp = get_option('seccomp')
+want_thread_safety = get_option('thread-safety')
+want_memfd_rexec = get_option('memfd-rexec')
+want_dbus = get_option('dbus')
 
 srcconf.set_quoted('DEFAULT_CGROUP_PATTERN', cgrouppattern)
+if coverity
+    srcconf.set('ENABLE_COVERITY_BUILD', 1)
+endif
 
 dummy_config_data = configuration_data()
 dummy_config_data.set_quoted('DUMMY_VARIABLE', '1')
 
+# Those generate many false positives, and we do not want to change the code to
+# avoid them.
+basic_disabled_warnings = [
+        '-Wno-format-signedness',
+        '-Wno-missing-field-initializers',
+        '-Wno-unused-parameter',
+]
+
 # Build flags.
 possible_cc_flags = [
     '-Wvla',
@@ -149,7 +189,6 @@ possible_cc_flags = [
     '-Wstrict-prototypes',
     '-fno-strict-aliasing',
     '-fstack-clash-protection',
-    '-fstack-protector-strong',
     '--param=ssp-buffer-size=4',
     '--mcet -fcf-protection',
     '-Werror=implicit-function-declaration',
@@ -182,20 +221,46 @@ possible_cc_flags = [
 ]
 
 possible_link_flags = [
+    '-Wl,--no-as-needed',
     '-Wl,--gc-sections',
     '-Wl,-z,relro',
     '-Wl,-z,now',
-    '-Wl,-fuse-ld=gold',
+    '-fstack-protector',
+    '-fstack-protector-strong',
 ]
 
+# The gold linker fails with a bus error on sparc64
+if build_machine.cpu_family() != 'sparc64'
+    possible_link_flags += '-Wl,-fuse-ld=gold'
+endif
+
+if sanitize == 'none'
+    possible_link_flags += '-Wl,--warn-common'
+endif
+
+if cc.get_id() == 'clang'
+    possible_cc_flags += [
+            '-Wno-typedef-redefinition',
+            '-Wno-gnu-variable-sized-type-not-at-end',
+    ]
+endif
+
 if meson.version().version_compare('>=0.46')
     add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language: 'c')
 else
     add_project_link_arguments(possible_link_flags, language: 'c')
 endif
 
+add_project_arguments(cc.get_supported_arguments(basic_disabled_warnings), language : 'c')
 add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language: 'c')
 
+if add_languages('cpp', required : want_oss_fuzz)
+    #  Used only for tests
+    cxx = meson.get_compiler('cpp')
+    cxx_cmd = ' '.join(cxx.cmd_array())
+    add_project_arguments(cxx.get_supported_arguments(basic_disabled_warnings), language : 'cpp')
+endif
+
 # Feature detection
 ## I/O uring.
 if want_io_uring
@@ -203,8 +268,21 @@ if want_io_uring
     if cc.has_function('io_uring_prep_poll_add', prefix: '#include <liburing.h>', dependencies: liburing) == false
         error('liburing version does not support IORING_POLL_ADD_MULTI')
     endif
+    pkgconfig_libs += liburing
+    liblxc_dependencies += liburing
 
     srcconf.set10('HAVE_LIBURING', true)
+else
+    srcconf.set10('HAVE_LIBURING', false)
+endif
+
+if want_dbus
+    libdbus = dependency('dbus-1', required: true)
+    pkgconfig_libs += libdbus
+    liblxc_dependencies += libdbus
+    srcconf.set10('HAVE_DBUS', libdbus.found())
+else
+    srcconf.set10('HAVE_DBUS', false)
 endif
 
 ## Time EPOCH.
@@ -214,18 +292,19 @@ git = find_program('git', required: false)
 time_epoch = run_command(sh, '-c', 'echo "$SOURCE_DATE_EPOCH"', check: true).stdout().strip()
 if time_epoch == '' and git.found() and run_command('test', '-e', '.git', check: false).returncode() == 0
     # If we're in a git repository, use the creation time of the latest git tag.
-    latest_tag = run_command(git, 'describe', '--abbrev=0', '--tags', check: true).stdout().strip()
-    time_epoch = run_command(git, 'log', '--no-show-signature', '-1', '--format=%at', latest_tag, check: true).stdout()
-else
-    # Fallback to current epoch.
-    time_epoch = run_command(date, '+%s', check: true).stdout()
+    latest_tag = run_command(git, 'describe', '--abbrev=0', '--tags', check: false).stdout().strip()
+    if latest_tag != ''
+      time_epoch = run_command(git, 'log', '--no-show-signature', '-1', '--format=%at', latest_tag, check: true).stdout().strip()
+    endif
+endif
+
+# Fallback to current epoch.
+if time_epoch == ''
+    time_epoch = run_command(date, '+%s', check: true).stdout().strip()
 endif
 generate_date = run_command(date, '--utc', '--date=@' + time_epoch, '+%Y-%m-%d', check: true).stdout().strip()
 
 ## Manpages.
-sgml2man = find_program('docbook2X2man', 'docbook2x-man', 'db2x_docbook2man', 'docbook2man', 'docbook-to-man', required: want_mans)
-docbook2man = find_program('docbook2man', required: false)
-
 docconf = configuration_data()
 docconf.set('builddir', '.')
 docconf.set('BINDIR', bindir)
@@ -240,82 +319,140 @@ docconf.set('LXCTEMPLATEDIR', lxctemplatedir)
 docconf.set('LXC_USERNIC_CONF', lxc_user_network_conf)
 docconf.set('LXC_USERNIC_DB', lxc_user_network_db)
 docconf.set('PACKAGE_VERSION', version_data.get('LXC_VERSION'))
-if sgml2man.found() and docbook2man.found() and sgml2man.full_path() == docbook2man.full_path()
-    docconf.set('docdtd', '"-//Davenport//DTD DocBook V3.0//EN"')
-else
-    docconf.set('docdtd', '"-//OASIS//DTD DocBook XML" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"')
+docconf.set('docdtd', '"-//OASIS//DTD DocBook XML" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"')
+sgml2man = find_program('docbook2X2man', 'docbook2x-man', 'db2x_docbook2man', 'docbook2man', 'docbook-to-man', required: false, version: '>=0.8')
+if not sgml2man.found()
+    sgml2man = find_program('docbook2man', required: false, version: '<0.8')
+    if sgml2man.found()
+        docconf.set('docdtd', '"-//Davenport//DTD DocBook V3.0//EN"')
+    elif want_mans
+        error('missing required docbook2x or docbook-utils dependency')
+    endif
 endif
 
 ## Threads.
 threads = dependency('threads')
+liblxc_dependencies += threads
 
 ## Seccomp.
-libseccomp = dependency('libseccomp')
-srcconf.set10('HAVE_SECCOMP', libseccomp.found())
-pkgconfig_libs += libseccomp
-if libseccomp.found()
-    if libseccomp.version().version_compare('>=2.5.0')
-        # https://github.com/seccomp/libseccomp/commit/dead12bc788b259b148cc4d93b970ef0bd602b1a
-        srcconf.set10('HAVE_DECL_SECCOMP_NOTIFY_FD', true)
-    else
-        srcconf.set10('HAVE_DECL_SECCOMP_NOTIFY_FD', false)
-    endif
-
-    if libseccomp.version().version_compare('>=2.0.0')
-        # https://github.com/seccomp/libseccomp/commit/6220c8c0fc479d97b6d3e3166a4e46fbfe25a3c0
-        srcconf.set10('HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH', true)
-    else
-        srcconf.set10('HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH', false)
-    endif
-
-    seccomp_headers = '''
-    #include <seccomp.h>
-    '''
-
-    foreach decl: [
-        'scmp_filter_ctx',
-        'struct seccomp_notif_sizes',
-        'struct clone_args',
-    ]
+if want_seccomp
+    libseccomp = dependency('libseccomp', required: false)
+    srcconf.set10('HAVE_SECCOMP', libseccomp.found())
+    pkgconfig_libs += libseccomp
+    liblxc_dependencies += libseccomp
+    if libseccomp.found()
+        if libseccomp.version().version_compare('>=2.5.0')
+            # https://github.com/seccomp/libseccomp/commit/dead12bc788b259b148cc4d93b970ef0bd602b1a
+            srcconf.set10('HAVE_DECL_SECCOMP_NOTIFY_FD', true)
+        else
+            srcconf.set10('HAVE_DECL_SECCOMP_NOTIFY_FD', false)
+        endif
 
-        # We get -1 if the size cannot be determined
-        if cc.sizeof(decl, prefix: seccomp_headers, args: '-D_GNU_SOURCE') > 0
-            srcconf.set10('HAVE_' + decl.underscorify().to_upper(), true)
+        if libseccomp.version().version_compare('>=2.0.0')
+            # https://github.com/seccomp/libseccomp/commit/6220c8c0fc479d97b6d3e3166a4e46fbfe25a3c0
+            srcconf.set10('HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH', true)
         else
-            srcconf.set10('HAVE_' + decl.underscorify().to_upper(), false)
+            srcconf.set10('HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH', false)
         endif
-    endforeach
+
+        seccomp_headers = '''
+        #include <seccomp.h>
+        '''
+
+        foreach decl: [
+            'scmp_filter_ctx',
+            'struct seccomp_notif_sizes',
+            'struct clone_args',
+        ]
+
+            # We get -1 if the size cannot be determined
+            if cc.sizeof(decl, prefix: seccomp_headers, args: '-D_GNU_SOURCE', dependencies: libseccomp) > 0
+                srcconf.set10('HAVE_' + decl.underscorify().to_upper(), true)
+            else
+                srcconf.set10('HAVE_' + decl.underscorify().to_upper(), false)
+            endif
+        endforeach
+    endif
+else
+    srcconf.set10('HAVE_SECCOMP', false)
 endif
 
 ## SELinux.
-libselinux = dependency('libselinux', required: false)
-srcconf.set10('HAVE_SELINUX', libselinux.found())
-pkgconfig_libs += libselinux
+if want_selinux
+    libselinux = dependency('libselinux', required: false)
+    srcconf.set10('HAVE_SELINUX', libselinux.found())
+    pkgconfig_libs += libselinux
+    liblxc_dependencies += libselinux
+else
+    srcconf.set10('HAVE_SELINUX', false)
+endif
 
 ## AppArmor.
-libapparmor = dependency('libapparmor', required: false)
-srcconf.set10('HAVE_APPARMOR', libapparmor.found())
+if want_apparmor
+    libapparmor = dependency('libapparmor', required: false)
+    srcconf.set10('HAVE_APPARMOR', libapparmor.found())
+    # We do not use the AppArmor library at runtime, so it's not in our pkg-config.
+    liblxc_dependencies += libapparmor
+else
+    srcconf.set10('HAVE_APPARMOR', false)
+endif
 
 ## OpenSSL.
-libopenssl = dependency('openssl', required: false)
-srcconf.set10('HAVE_OPENSSL', libopenssl.found())
-pkgconfig_libs += libopenssl
+if want_openssl
+    libopenssl = dependency('openssl', required: false)
+    srcconf.set10('HAVE_OPENSSL', libopenssl.found())
+    pkgconfig_libs += libopenssl
+    liblxc_dependencies += libopenssl
+else
+    srcconf.set10('HAVE_OPENSSL', false)
+endif
 
 ## Libcap..
-libcap = dependency('libcap', required: false)
-if not libcap.found()
-    # Compat with Ubuntu 14.04 which ships libcap w/o .pc file
-    libcap = cc.find_library('cap', required: false)
+if want_capabilities
+    libcap = dependency('libcap', required: false)
+    if not libcap.found()
+        # Compat with Ubuntu 14.04 which ships libcap w/o .pc file
+        libcap = cc.find_library('cap', required: false)
+    else
+        have = cc.has_function('cap_get_file', dependencies: libcap, prefix: '#include <sys/capability.h>')
+        srcconf.set10('LIBCAP_SUPPORTS_FILE_CAPABILITIES', have)
+    endif
+    srcconf.set10('HAVE_LIBCAP', libcap.found())
+    pkgconfig_libs += libcap
+    liblxc_dependencies += libcap
+
+    libcap_static = dependency('libcap', required: false, static: true)
+    if not libcap_static.found()
+        # Compat with Ubuntu 14.04 which ships libcap w/o .pc file
+        libcap_static = cc.find_library('cap', required: false, static: true)
+    endif
+
+    code = '''
+int main(int argc, char *argv[]) { return 0; };
+'''
+    if libcap_static.found()
+        libcap_static_linkable = cc.links(code, args: '-static', dependencies: libcap_static)
+    else
+        libcap_static_linkable = false
+    endif
+    srcconf.set10('HAVE_STATIC_LIBCAP', libcap_static_linkable)
+else
+    libcap_static = []
+    libcap_static_linkable = false
+    srcconf.set10('HAVE_LIBCAP', false)
+    srcconf.set10('HAVE_STATIC_LIBCAP', false)
 endif
-srcconf.set10('HAVE_LIBCAP', libcap.found())
-pkgconfig_libs += libcap
 
-libcap_static = dependency('libcap', required: false, static: true)
-if not libcap_static.found()
-    # Compat with Ubuntu 14.04 which ships libcap w/o .pc file
-    libcap_static = cc.find_library('cap', required: false, static: true)
+libutil = cc.find_library('util', required: false)
+
+if want_oss_fuzz
+    srcconf.set10('FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION', true)
+    srcconf.set10('RUN_ON_OSS_FUZZ', true)
+    fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
 endif
-srcconf.set10('HAVE_STATIC_LIBCAP', libcap_static.found())
+
+srcconf.set10('ENFORCE_THREAD_SAFETY', want_thread_safety)
+srcconf.set10('ENFORCE_MEMFD_REXEC', want_memfd_rexec)
 
 ## PAM.
 pam = cc.find_library('pam', has_headers: 'security/pam_modules.h', required: want_pam_cgroup)
@@ -323,11 +460,48 @@ srcconf.set10('HAVE_PAM', pam.found())
 pkgconfig_libs += pam
 
 ## Others.
+have = cc.has_function('fmemopen', prefix: '#include <stdio.h>', args: '-D_GNU_SOURCE')
+srcconf.set10('HAVE_FMEMOPEN', have)
+
+have = cc.has_function('openpty', dependencies: libutil, prefix: '#include <pty.h>')
+srcconf.set10('HAVE_OPENPTY', have)
+if have
+    liblxc_dependencies += libutil
+    if want_oss_fuzz
+        oss_fuzz_dependencies += libutil
+    endif
+endif
+
+have = cc.has_function('pthread_setcancelstate', prefix: '#include <pthread.h>')
+srcconf.set10('HAVE_PTHREAD_SETCANCELSTATE', have)
+
+have = cc.has_function('rand_r')
+srcconf.set10('HAVE_RAND_R', have)
+
 have = cc.has_function('strchrnul', prefix: '#include <string.h>', args: '-D_GNU_SOURCE')
 srcconf.set10('HAVE_STRCHRNUL', have)
 
-have = cc.has_function('openpty', prefix: '#include <pty.h>', args: '-D_GNU_SOURCE')
-srcconf.set10('HAVE_OPENPTY', have)
+have_func_strerror_r = cc.has_function('strerror_r', prefix: '#include <string.h>', args: '-D_GNU_SOURCE')
+srcconf.set10('HAVE_STRERROR_R', have_func_strerror_r)
+
+have_func_strerror_r_char_p = false
+
+if have_func_strerror_r
+    code = '''
+#define _GNU_SOURCE
+#include <string.h>
+int func (void) {
+    char error_string[256];
+    char *ptr = strerror_r (-2, error_string, 256);
+    char c = *strerror_r (-2, error_string, 256);
+    return c != 0 && ptr != (void*) 0L;
+}
+'''
+
+have_func_strerror_r_char_p = cc.compiles(code, name : 'strerror_r() returns char *')
+endif
+
+srcconf.set10('STRERROR_R_CHAR_P', have_func_strerror_r_char_p)
 
 ## Compiler attributes.
 foreach ccattr: [
@@ -349,6 +523,7 @@ foreach tuple: [
     ['execveat'],
     ['faccessat'],
     ['strchrnul'],
+    ['strerror_r'],
     ['fgetln'],
     ['fsconfig'],
     ['fsmount'],
@@ -379,6 +554,7 @@ foreach tuple: [
     ['sigdescr_np'],
     ['signalfd'],
     ['statx'],
+    ['statvfs'],
     ['strlcat'],
     ['strlcpy'],
     ['unshare'],
@@ -404,17 +580,15 @@ decl_headers = '''
 #include <uchar.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#include <linux/fs.h>
+#include <linux/if_link.h>
 #include <linux/types.h>
-#include <linux/openat2.h>
-#include <linux/sched.h>
 '''
 
 foreach decl: [
     '__aligned_u64',
-    'struct mount_attr',
-    'struct open_how',
     'struct clone_args',
+    'struct open_how',
+    'struct rtnl_link_stats64',
 ]
 
     # We get -1 if the size cannot be determined
@@ -432,8 +606,8 @@ foreach tuple: [
     ['struct seccomp_notif_sizes'],
     ['struct clone_args'],
     ['__aligned_u64'],
-    ['struct mount_attr'],
     ['struct open_how'],
+    ['struct rtnl_link_stats64'],
 ]
 
     if tuple.length() >= 2
@@ -451,6 +625,75 @@ foreach tuple: [
     endif
 endforeach
 
+decl_headers = '''
+#include <sys/mount.h>
+'''
+
+# We get -1 if the size cannot be determined
+if cc.sizeof('struct mount_attr', prefix: decl_headers, args: '-D_GNU_SOURCE') > 0
+    srcconf.set10('HAVE_' + 'struct mount_attr'.underscorify().to_upper(), true)
+    found_types += 'struct mount_attr (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'struct mount_attr'.underscorify().to_upper(), false)
+    missing_types += 'struct mount_attr (sys/mount.h)' endif
+
+## Check if sys/mount.h defines the fsconfig commands
+if cc.get_define('FSCONFIG_SET_FLAG', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FSCONFIG_SET_FLAG'.underscorify().to_upper(), true)
+    found_types += 'FSCONFIG_SET_FLAG (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FSCONFIG_SET_FLAG'.underscorify().to_upper(), false)
+    missing_types += 'FSCONFIG_SET_FLAG (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_STRING', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_STRING'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_STRING (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_STRING'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_STRING (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_BINARY', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_BINARY'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_BINARY (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_BINARY'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_BINARY (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_PATH_EMPTY', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_PATH_EMPTY'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_PATH_EMPTY (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_PATH_EMPTY'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_PATH_EMPTY (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_PATH_FD', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_PATH_FD'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_PATH_FD (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_PATH_FD'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_PATH_FD (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_CMD_CREATE', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_CMD_CREATE'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_CMD_CREAT (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_CMD_CREATE'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_CMD_CREATE (sys/mount.h)'
+endif
+
+if cc.get_define('FS_CONFIG_SET_CMD_RECONFIGURE', prefix: decl_headers) != ''
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_CMD_RECONFIGURE'.underscorify().to_upper(), true)
+    found_types += 'FS_CONFIG_SET_CMD_RECONFIGURE (sys/mount.h)'
+else
+    srcconf.set10('HAVE_' + 'FS_CONFIG_SET_CMD_RECONFIGURE'.underscorify().to_upper(), false)
+    missing_types += 'FS_CONFIG_SET_CMD_RECONFIGURE (sys/mount.h)'
+endif
+
 ## Headers.
 foreach ident: [
     ['bpf',               '''#include <sys/syscall.h>
@@ -508,6 +751,7 @@ foreach ident: [
     ['setns',             '''#include <sched.h>'''],
     ['sigdescr_np',       '''#include <string.h>'''],
     ['signalfd',          '''#include <sys/signalfd.h>'''],
+    ['statvfs',           '''#include <sys/statvfs.h>'''],
     ['statx',             '''#include <sys/types.h>
                              #include <sys/stat.h>
                              #include <unistd.h>'''],
@@ -527,6 +771,7 @@ foreach tuple: [
     ['sys/resource.h'],
     ['sys/memfd.h'],
     ['sys/personality.h'],
+    ['sys/pidfd.h'],
     ['sys/signalfd.h'],
     ['sys/timerfd.h'],
     ['pty.h'],
@@ -593,34 +838,28 @@ template_scripts = []
 test_programs = []
 
 # Includes.
-basic_includes = include_directories(
+liblxc_includes = include_directories(
     '.',
     'src',
-    'src/include')
-
-liblxc_includes = [basic_includes, include_directories(
+    'src/include',
+    'src/lxc',
     'src/lxc/cgroups',
-    'src/lxc/lsm',
-    'src/lxc/storage')]
+    'src/lxc/storage')
+
+# Our static sub-project binaries don't (and in fact can't) link to our
+# dependencies directly, but need access to the headers when compiling (most
+# notably seccomp headers).
+liblxc_dependency_headers = []
+foreach dep: liblxc_dependencies
+    liblxc_dependency_headers += dep.partial_dependency(compile_args: true)
+endforeach
 
 # Early sub-directories.
 subdir('src/include')
 subdir('src/lxc')
 subdir('src/lxc/pam')
 
-# Library.
-liblxc_dependencies = [
-    threads,
-    libseccomp,
-    libcap,
-    libopenssl,
-    libselinux,
-    libapparmor,
-]
-
-if want_io_uring
-    liblxc_dependencies += [liburing]
-endif
+liblxc_link_whole = [liblxc_static]
 
 liblxc = shared_library(
     'lxc',
@@ -628,7 +867,7 @@ liblxc = shared_library(
     include_directories: liblxc_includes,
     link_args: ['-DPIC'],
     c_args: ['-DPIC'],
-    link_whole: [liblxc_static],
+    link_whole: liblxc_link_whole,
     dependencies: liblxc_dependencies,
     install: true)
 
@@ -637,16 +876,20 @@ liblxc_dep = declare_dependency(
     dependencies: liblxc_dependencies)
 
 # Rest of sub-directories.
-subdir('config/apparmor')
-subdir('config/apparmor/abstractions')
-subdir('config/apparmor/profiles')
+if want_apparmor
+    subdir('config/apparmor')
+    subdir('config/apparmor/abstractions')
+    subdir('config/apparmor/profiles')
+endif
 subdir('config/bash')
 subdir('config/etc')
 subdir('config/init/common')
 subdir('config/init/systemd')
 subdir('config/init/sysvinit')
 subdir('config/init/upstart')
-subdir('config/selinux')
+if want_selinux
+    subdir('config/selinux')
+endif
 subdir('config/sysconfig')
 subdir('config/templates')
 subdir('config/templates/common.conf.d')
@@ -657,8 +900,12 @@ subdir('doc/ko')
 subdir('doc/examples')
 subdir('doc/rootfs')
 subdir('hooks')
-subdir('src/lxc/cmd')
-subdir('src/lxc/tools')
+if want_commands
+    subdir('src/lxc/cmd')
+endif
+if want_tools or want_tools_multicall
+    subdir('src/lxc/tools')
+endif
 subdir('src/lxc/tools/include')
 subdir('src/tests')
 subdir('templates')
@@ -677,8 +924,14 @@ install_emptydir(join_paths(localstatedir, 'cache', 'lxc'))
 install_emptydir(join_paths(localstatedir, 'lib', 'lxc'))
 
 # RPM spec file.
+specconf = configuration_data()
+specconf.set('LXC_VERSION_BASE', meson.project_version())
+specconf.set('LXC_VERSION_BETA', version_data.get('LXC_VERSION_BETA'))
+specconf.set('PACKAGE', meson.project_name())
+specconf.set('LXC_DISTRO_SYSCONF', conf.get('LXC_DISTRO_SYSCONF'))
+
 configure_file(
-    configuration: conf,
+    configuration: specconf,
     input: 'lxc.spec.in',
     output: 'lxc.spec',
     install: false)