shell-completions: install new completions which were forgotten
[systemd.io.git] / meson.build
blobcecdbc3aa7b9434d09b6b2e6f253fa817f985456
1 # SPDX-License-Identifier: LGPL-2.1-or-later
3 project('systemd', 'c',
4         version : files('meson.version'),
5         license : 'LGPLv2+',
6         default_options: [
7                 'c_std=gnu11',
8                 'prefix=/usr',
9                 'sysconfdir=/etc',
10                 'localstatedir=/var',
11                 'warning_level=2',
12         ],
13         meson_version : '>= 0.60.0',
14        )
16 libsystemd_version = '0.39.0'
17 libudev_version = '1.7.9'
19 conf = configuration_data()
20 conf.set_quoted('PROJECT_URL', 'https://systemd.io/')
21 conf.set('PROJECT_VERSION', meson.project_version().split('~')[0],
22          description : 'Numerical project version (used where a simple number is expected)')
23 conf.set_quoted('PROJECT_VERSION_FULL', meson.project_version(), description : 'Full project version')
25 # This is to be used instead of meson.source_root(), as the latter will return
26 # the wrong result when systemd is being built as a meson subproject
27 project_source_root = meson.current_source_dir()
28 project_build_root = meson.current_build_dir()
29 relative_source_path = run_command('realpath',
30                                    '--relative-to=@0@'.format(project_build_root),
31                                    project_source_root,
32                                    check : true).stdout().strip()
33 conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path)
35 conf.set10('BUILD_MODE_DEVELOPER', get_option('mode') == 'developer',
36            description : 'tailor build to development or release builds')
38 feature = get_option('log-message-verification')
39 if feature.auto()
40         have = conf.get('BUILD_MODE_DEVELOPER') == 1
41 else
42         have = feature.enabled()
43 endif
44 conf.set10('LOG_MESSAGE_VERIFICATION', have)
46 want_ossfuzz = get_option('oss-fuzz')
47 want_libfuzzer = get_option('llvm-fuzz')
48 if want_ossfuzz and want_libfuzzer
49         error('only one of oss-fuzz or llvm-fuzz can be specified')
50 endif
52 fuzzer_build = want_ossfuzz or want_libfuzzer
54 # If we're building *not* for actual fuzzing, allow input samples of any size
55 # (for testing and for reproduction of issues discovered with previously-higher
56 # limits).
57 conf.set10('FUZZ_USE_SIZE_LIMIT', fuzzer_build)
59 # We'll set this to '1' for EFI builds in a different place.
60 conf.set10('SD_BOOT', false)
62 # Create a title-less summary section early, so it ends up first in the output.
63 # More items are added later after they have been detected.
64 summary({'build mode' : get_option('mode')})
66 #####################################################################
68 # Try to install the git pre-commit hook
69 git_setup_sh = find_program('tools/git-setup.sh', required : false)
70 if git_setup_sh.found()
71         git_hook = run_command(git_setup_sh, check : false)
72         if git_hook.returncode() == 0
73                 message(git_hook.stdout().strip())
74         endif
75 endif
77 #####################################################################
79 fs = import('fs')
80 if get_option('split-bin') == 'auto'
81         split_bin = not fs.is_symlink('/usr/sbin')
82 else
83         split_bin = get_option('split-bin') == 'true'
84 endif
85 conf.set10('HAVE_SPLIT_BIN', split_bin,
86            description : 'bin and sbin directories are separate')
88 have_standalone_binaries = get_option('standalone-binaries')
90 sysvinit_path = get_option('sysvinit-path')
91 sysvrcnd_path = get_option('sysvrcnd-path')
92 conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
93            description : 'SysV init scripts and rcN.d links are supported')
94 conf.set10('CREATE_LOG_DIRS', get_option('create-log-dirs'))
96 if get_option('hibernate') and not get_option('initrd')
97         error('hibernate depends on initrd')
98 endif
100 conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
101 conf.set10('BUMP_PROC_SYS_FS_NR_OPEN',  get_option('bump-proc-sys-fs-nr-open'))
102 conf.set('HIGH_RLIMIT_NOFILE',          512*1024)
104 # Meson ignores the preceding arguments when joining paths if an absolute
105 # component is encountered, so this should canonicalize various paths when they
106 # are absolute or relative.
107 prefixdir = get_option('prefix')
108 if not prefixdir.startswith('/')
109         error('Prefix is not absolute: "@0@"'.format(prefixdir))
110 endif
112 prefixdir_noslash = '/' + prefixdir.strip('/')
113 bindir = prefixdir / get_option('bindir')
114 sbindir = prefixdir / (split_bin ? 'sbin' : 'bin')
115 sbin_to_bin = split_bin ? '../bin/' : ''
116 libdir = prefixdir / get_option('libdir')
117 sysconfdir = prefixdir / get_option('sysconfdir')
118 includedir = prefixdir / get_option('includedir')
119 datadir = prefixdir / get_option('datadir')
120 localstatedir = '/' / get_option('localstatedir')
122 libexecdir = prefixdir / 'lib/systemd'
123 pkglibdir = libdir / 'systemd'
125 install_sysconfdir = get_option('install-sysconfdir') != 'false'
126 install_sysconfdir_samples = get_option('install-sysconfdir') == 'true'
127 # Dirs of external packages
128 pkgconfigdatadir = get_option('pkgconfigdatadir') != '' ? get_option('pkgconfigdatadir') : datadir / 'pkgconfig'
129 pkgconfiglibdir = get_option('pkgconfiglibdir') != '' ? get_option('pkgconfiglibdir') : libdir / 'pkgconfig'
130 polkitpolicydir = datadir / 'polkit-1/actions'
131 polkitrulesdir = datadir / 'polkit-1/rules.d'
132 polkitpkladir = localstatedir / 'lib/polkit-1/localauthority/10-vendor.d'
133 xinitrcdir = get_option('xinitrcdir') != '' ? get_option('xinitrcdir') : sysconfdir / 'X11/xinit/xinitrc.d'
134 rpmmacrosdir = get_option('rpmmacrosdir')
135 if rpmmacrosdir != 'no'
136         rpmmacrosdir = prefixdir / rpmmacrosdir
137 endif
138 modprobedir = prefixdir / 'lib/modprobe.d'
140 # Our own paths
141 pkgdatadir = datadir / 'systemd'
142 environmentdir = prefixdir / 'lib/environment.d'
143 pkgsysconfdir = sysconfdir / 'systemd'
144 userunitdir = prefixdir / 'lib/systemd/user'
145 userpresetdir = prefixdir / 'lib/systemd/user-preset'
146 tmpfilesdir = prefixdir / 'lib/tmpfiles.d'
147 usertmpfilesdir = prefixdir / 'share/user-tmpfiles.d'
148 sysusersdir = prefixdir / 'lib/sysusers.d'
149 sysctldir = prefixdir / 'lib/sysctl.d'
150 binfmtdir = prefixdir / 'lib/binfmt.d'
151 modulesloaddir = prefixdir / 'lib/modules-load.d'
152 networkdir = prefixdir / 'lib/systemd/network'
153 systemgeneratordir = libexecdir / 'system-generators'
154 usergeneratordir = prefixdir / 'lib/systemd/user-generators'
155 systemenvgeneratordir = prefixdir / 'lib/systemd/system-environment-generators'
156 userenvgeneratordir = prefixdir / 'lib/systemd/user-environment-generators'
157 systemshutdowndir = libexecdir / 'system-shutdown'
158 systemsleepdir = libexecdir / 'system-sleep'
159 systemunitdir = prefixdir / 'lib/systemd/system'
160 systempresetdir = prefixdir / 'lib/systemd/system-preset'
161 udevlibexecdir = prefixdir / 'lib/udev'
162 udevrulesdir = udevlibexecdir / 'rules.d'
163 udevhwdbdir = udevlibexecdir / 'hwdb.d'
164 catalogdir = prefixdir / 'lib/systemd/catalog'
165 kerneldir = prefixdir / 'lib/kernel'
166 kernelinstalldir = kerneldir / 'install.d'
167 factorydir = datadir / 'factory'
168 bootlibdir = prefixdir / 'lib/systemd/boot/efi'
169 testsdir = prefixdir / 'lib/systemd/tests'
170 unittestsdir = testsdir / 'unit-tests'
171 testdata_dir = testsdir / 'testdata'
172 systemdstatedir = localstatedir / 'lib/systemd'
173 catalogstatedir = systemdstatedir / 'catalog'
174 randomseeddir = localstatedir / 'lib/systemd'
175 profiledir = libexecdir / 'portable' / 'profile'
176 repartdefinitionsdir = libexecdir / 'repart/definitions'
177 ntpservicelistdir = prefixdir / 'lib/systemd/ntp-units.d'
178 credstoredir = prefixdir / 'lib/credstore'
179 pcrlockdir = prefixdir / 'lib/pcrlock.d'
180 mimepackagesdir = prefixdir / 'share/mime/packages'
182 configfiledir = get_option('configfiledir')
183 if configfiledir == ''
184         configfiledir= sysconfdir
185 endif
186 pkgconfigfiledir = configfiledir / 'systemd'
188 docdir = get_option('docdir')
189 if docdir == ''
190         docdir = datadir / 'doc/systemd'
191 endif
193 pamlibdir = get_option('pamlibdir')
194 if pamlibdir == ''
195         pamlibdir = libdir / 'security'
196 endif
198 pamconfdir = get_option('pamconfdir')
199 if pamconfdir == ''
200         pamconfdir = prefixdir / 'lib/pam.d'
201 endif
203 sshconfdir = get_option('sshconfdir')
204 if sshconfdir == ''
205         sshconfdir = sysconfdir / 'ssh/ssh_config.d'
206 endif
208 sshdconfdir = get_option('sshdconfdir')
209 if sshdconfdir == ''
210         sshdconfdir = sysconfdir / 'ssh/sshd_config.d'
211 endif
213 sshdprivsepdir = get_option('sshdprivsepdir')
214 conf.set10('CREATE_SSHDPRIVSEPDIR', sshdprivsepdir != 'no' and not sshdprivsepdir.startswith('/usr/'))
215 conf.set('SSHDPRIVSEPDIR', sshdprivsepdir, description : 'SSH privilege separation directory')
217 libcryptsetup_plugins_dir = get_option('libcryptsetup-plugins-dir')
218 if libcryptsetup_plugins_dir == ''
219         libcryptsetup_plugins_dir = libdir / 'cryptsetup'
220 endif
222 memory_accounting_default = get_option('memory-accounting-default')
223 status_unit_format_default = get_option('status-unit-format-default')
224 if status_unit_format_default == 'auto'
225         status_unit_format_default = conf.get('BUILD_MODE_DEVELOPER') == 1 ? 'name' : 'description'
226 endif
228 conf.set_quoted('BINDIR',                                     bindir)
229 conf.set_quoted('BINFMT_DIR',                                 binfmtdir)
230 conf.set_quoted('BOOTLIBDIR',                                 bootlibdir)
231 conf.set_quoted('CATALOG_DATABASE',                           catalogstatedir / 'database')
232 conf.set_quoted('CERTIFICATE_ROOT',                           get_option('certificate-root'))
233 conf.set_quoted('DOC_DIR',                                    docdir)
234 conf.set_quoted('DOCUMENT_ROOT',                              pkgdatadir / 'gatewayd')
235 conf.set_quoted('ENVIRONMENT_DIR',                            environmentdir)
236 conf.set_quoted('INCLUDE_DIR',                                includedir)
237 conf.set_quoted('LIBDIR',                                     libdir)
238 conf.set_quoted('LIBEXECDIR',                                 libexecdir)
239 conf.set_quoted('KERNEL_INSTALL_DIR',                         kernelinstalldir)
240 conf.set_quoted('MODPROBE_DIR',                               modprobedir)
241 conf.set_quoted('MODULESLOAD_DIR',                            modulesloaddir)
242 conf.set_quoted('PKGSYSCONFDIR',                              pkgsysconfdir)
243 conf.set_quoted('POLKIT_AGENT_BINARY_PATH',                   bindir / 'pkttyagent')
244 conf.set_quoted('PREFIX',                                     prefixdir)
245 conf.set_quoted('PREFIX_NOSLASH',                             prefixdir_noslash)
246 conf.set_quoted('RANDOM_SEED',                                randomseeddir / 'random-seed')
247 conf.set_quoted('RANDOM_SEED_DIR',                            randomseeddir)
248 conf.set_quoted('RC_LOCAL_PATH',                              get_option('rc-local'))
249 conf.set_quoted('SSHCONFDIR',                                 sshconfdir)
250 conf.set_quoted('SSHDCONFDIR',                                sshdconfdir)
251 conf.set_quoted('SYSCONF_DIR',                                sysconfdir)
252 conf.set_quoted('SYSCTL_DIR',                                 sysctldir)
253 conf.set_quoted('SYSTEMCTL_BINARY_PATH',                      bindir / 'systemctl')
254 conf.set_quoted('SYSTEMD_BINARY_PATH',                        libexecdir / 'systemd')
255 conf.set_quoted('SYSTEMD_EXECUTOR_BINARY_PATH',               libexecdir / 'systemd-executor')
256 conf.set_quoted('SYSTEMD_CATALOG_DIR',                        catalogdir)
257 conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH',                 libexecdir / 'systemd-cgroups-agent')
258 conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH',                    bindir / 'systemd-cryptsetup')
259 conf.set_quoted('SYSTEMD_EXPORT_PATH',                        libexecdir / 'systemd-export')
260 conf.set_quoted('SYSTEMD_FSCK_PATH',                          libexecdir / 'systemd-fsck')
261 conf.set_quoted('SYSTEMD_GROWFS_PATH',                        libexecdir / 'systemd-growfs')
262 conf.set_quoted('SYSTEMD_HOMEWORK_PATH',                      libexecdir / 'systemd-homework')
263 conf.set_quoted('SYSTEMD_IMPORT_FS_PATH',                     libexecdir / 'systemd-import-fs')
264 conf.set_quoted('SYSTEMD_IMPORT_PATH',                        libexecdir / 'systemd-import')
265 conf.set_quoted('SYSTEMD_INTEGRITYSETUP_PATH',                libexecdir / 'systemd-integritysetup')
266 conf.set_quoted('SYSTEMD_KBD_MODEL_MAP',                      pkgdatadir / 'kbd-model-map')
267 conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP',              pkgdatadir / 'language-fallback-map')
268 conf.set_quoted('SYSTEMD_MAKEFS_PATH',                        libexecdir / 'systemd-makefs')
269 conf.set_quoted('SYSTEMD_PULL_PATH',                          libexecdir / 'systemd-pull')
270 conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH',               libexecdir / 'systemd-shutdown')
271 conf.set_quoted('SYSTEMD_TEST_DATA',                          testdata_dir)
272 conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', bindir / 'systemd-tty-ask-password-agent')
273 conf.set_quoted('SYSTEMD_UPDATE_HELPER_PATH',                 libexecdir / 'systemd-update-helper')
274 conf.set_quoted('SYSTEMD_USERWORK_PATH',                      libexecdir / 'systemd-userwork')
275 conf.set_quoted('SYSTEMD_MOUNTWORK_PATH',                     libexecdir / 'systemd-mountwork')
276 conf.set_quoted('SYSTEMD_NSRESOURCEWORK_PATH',                libexecdir / 'systemd-nsresourcework')
277 conf.set_quoted('SYSTEMD_VERITYSETUP_PATH',                   libexecdir / 'systemd-veritysetup')
278 conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR',                     pkgsysconfdir / 'system')
279 conf.set_quoted('SYSTEM_DATA_UNIT_DIR',                       systemunitdir)
280 conf.set_quoted('SYSTEM_ENV_GENERATOR_DIR',                   systemenvgeneratordir)
281 conf.set_quoted('SYSTEM_GENERATOR_DIR',                       systemgeneratordir)
282 conf.set_quoted('SYSTEM_PRESET_DIR',                          systempresetdir)
283 conf.set_quoted('SYSTEM_SHUTDOWN_PATH',                       systemshutdowndir)
284 conf.set_quoted('SYSTEM_SLEEP_PATH',                          systemsleepdir)
285 conf.set_quoted('SYSTEM_SYSVINIT_PATH',                       sysvinit_path)
286 conf.set_quoted('SYSTEM_SYSVRCND_PATH',                       sysvrcnd_path)
287 conf.set_quoted('SYSUSERS_DIR',                               sysusersdir)
288 conf.set_quoted('TMPFILES_DIR',                               tmpfilesdir)
289 conf.set_quoted('USER_TMPFILES_DIR',                          usertmpfilesdir)
290 conf.set_quoted('UDEVLIBEXECDIR',                             udevlibexecdir)
291 conf.set_quoted('UDEV_HWDB_DIR',                              udevhwdbdir)
292 conf.set_quoted('UDEV_RULES_DIR',                             udevrulesdir)
293 conf.set_quoted('USER_CONFIG_UNIT_DIR',                       pkgsysconfdir / 'user')
294 conf.set_quoted('USER_DATA_UNIT_DIR',                         userunitdir)
295 conf.set_quoted('USER_ENV_GENERATOR_DIR',                     userenvgeneratordir)
296 conf.set_quoted('USER_GENERATOR_DIR',                         usergeneratordir)
297 conf.set_quoted('USER_KEYRING_PATH',                          pkgsysconfdir / 'import-pubring.gpg')
298 conf.set_quoted('USER_PRESET_DIR',                            userpresetdir)
299 conf.set_quoted('VENDOR_KEYRING_PATH',                        libexecdir / 'import-pubring.gpg')
301 conf.set('ANSI_OK_COLOR',                                     'ANSI_' + get_option('ok-color').underscorify().to_upper())
302 conf.set10('ENABLE_URLIFY',                                   get_option('urlify'))
303 conf.set10('ENABLE_FEXECVE',                                  get_option('fexecve'))
304 conf.set10('MEMORY_ACCOUNTING_DEFAULT',                       memory_accounting_default)
305 conf.set('STATUS_UNIT_FORMAT_DEFAULT',                        'STATUS_UNIT_FORMAT_' + status_unit_format_default.to_upper())
306 conf.set_quoted('STATUS_UNIT_FORMAT_DEFAULT_STR',             status_unit_format_default)
308 conf.set('DEFAULT_TIMEOUT_SEC',                               get_option('default-timeout-sec'))
309 conf.set('DEFAULT_USER_TIMEOUT_SEC',                          get_option('default-user-timeout-sec'))
310 conf.set('UPDATE_HELPER_USER_TIMEOUT_SEC',                    get_option('update-helper-user-timeout-sec'))
312 conf.set10('ENABLE_FIRST_BOOT_FULL_PRESET',                   get_option('first-boot-full-preset'))
314 #####################################################################
316 cc = meson.get_compiler('c')
317 userspace_c_args = []
318 userspace_c_ld_args = []
319 meson_build_sh = find_program('tools/meson-build.sh')
321 want_tests = get_option('tests')
322 slow_tests = want_tests != 'false' and get_option('slow-tests')
323 fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
324 integration_tests = want_tests != 'false' and get_option('integration-tests')
325 install_tests = want_tests != 'false' and get_option('install-tests')
327 if add_languages('cpp', native : false, required : fuzzer_build)
328         #  Used only for tests
329         cxx = meson.get_compiler('cpp')
330         cxx_cmd = ' '.join(cxx.cmd_array())
331 else
332         cxx_cmd = ''
333 endif
335 if want_libfuzzer
336         fuzzing_engine = meson.get_compiler('cpp').find_library('Fuzzer', required : false)
337         if fuzzing_engine.found()
338                 userspace_c_args += '-fsanitize-coverage=trace-pc-guard,trace-cmp'
339         elif cc.has_argument('-fsanitize=fuzzer-no-link')
340                 userspace_c_args += '-fsanitize=fuzzer-no-link'
341         else
342                 error('Looks like neither libFuzzer nor -fsanitize=fuzzer-no-link is supported')
343         endif
344 elif want_ossfuzz
345         fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
346 endif
348 # Those generate many false positives, and we do not want to change the code to
349 # avoid them.
350 basic_disabled_warnings = [
351         '-Wno-missing-field-initializers',
352         '-Wno-unused-parameter',
353         '-Wno-nonnull-compare',
356 possible_common_cc_flags = [
357         '-Warray-bounds',     # clang
358         '-Warray-bounds=2',
359         '-Wdate-time',
360         '-Wendif-labels',
361         '-Werror=format=2',
362         '-Werror=format-signedness',
363         '-Werror=implicit-function-declaration',
364         '-Werror=implicit-int',
365         '-Werror=incompatible-pointer-types',
366         '-Werror=int-conversion',
367         '-Werror=missing-declarations',
368         '-Werror=missing-prototypes',
369         '-Werror=overflow',
370         '-Werror=override-init',
371         '-Werror=return-type',
372         '-Werror=shift-count-overflow',
373         '-Werror=shift-overflow=2',
374         '-Werror=strict-flex-arrays',
375         '-Werror=undef',
376         '-Wfloat-equal',
377         # gperf prevents us from enabling this because it does not emit fallthrough
378         # attribute with clang.
379         #'-Wimplicit-fallthrough',
380         '-Wimplicit-fallthrough=5',
381         '-Winit-self',
382         '-Wlogical-op',
383         '-Wmissing-include-dirs',
384         '-Wmissing-noreturn',
385         '-Wnested-externs',
386         '-Wold-style-definition',
387         '-Wpointer-arith',
388         '-Wredundant-decls',
389         '-Wshadow',
390         '-Wstrict-aliasing=2',
391         '-Wstrict-prototypes',
392         '-Wsuggest-attribute=noreturn',
393         '-Wunused-function',
394         '-Wwrite-strings',
395         '-Wzero-length-bounds',
397         # negative arguments are correctly detected starting with meson 0.46.
398         '-Wno-error=#warnings',  # clang
399         '-Wno-string-plus-int',  # clang
401         '-fdiagnostics-show-option',
402         '-fno-common',
403         '-fstack-protector',
404         '-fstack-protector-strong',
405         '-fstrict-flex-arrays',
406         '--param=ssp-buffer-size=4',
409 possible_common_link_flags = [
410         '-fstack-protector',
413 c_args = get_option('c_args')
415 # Our json library does not support -ffinite-math-only, which is enabled by -Ofast or -ffast-math.
416 if (('-Ofast' in c_args or '-ffast-math' in c_args or '-ffinite-math-only' in c_args) and '-fno-finite-math-only' not in c_args)
417         error('-Ofast, -ffast-math, or -ffinite-math-only is specified in c_args.')
418 endif
420 # Disable -Wmaybe-uninitialized when compiling with -Os/-O1/-O3/etc. There are
421 # too many false positives with gcc >= 8. Effectively, we only test with -O0
422 # and -O2; this should be enough to catch most important cases without too much
423 # busywork. See https://github.com/systemd/systemd/pull/19226.
424 if cc.get_id() == 'gcc' and (not '02'.contains(get_option('optimization')) or
425                              cc.version().version_compare('<10') or
426                              '-Os' in c_args or
427                              '-O1' in c_args or
428                              '-O3' in c_args or
429                              '-Og' in c_args)
430         possible_common_cc_flags += '-Wno-maybe-uninitialized'
431 endif
433 # Disable -Wno-unused-result with gcc, see
434 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425.
435 if cc.get_id() == 'gcc'
436         possible_common_cc_flags += '-Wno-unused-result'
437 endif
439 # --as-needed and --no-undefined are provided by meson by default,
440 # run 'meson configure' to see what is enabled
441 possible_link_flags = [
442         '-Wl,--fatal-warnings',
443         '-Wl,-z,now',
444         '-Wl,-z,relro',
447 if get_option('b_sanitize') == 'none'
448         possible_link_flags += '-Wl,--warn-common'
449 endif
451 if cc.get_id() == 'clang'
452         possible_common_cc_flags += [
453                 '-Wno-typedef-redefinition',
454                 '-Wno-gnu-variable-sized-type-not-at-end',
455         ]
456 endif
458 if get_option('mode') == 'release'
459         # We could enable 'pattern' for developer mode, but that can interfere with
460         # valgrind and sanitizer builds. Also, clang does not zero-initialize unions,
461         # breaking some of our code (https://reviews.llvm.org/D68115).
462         possible_common_cc_flags += '-ftrivial-auto-var-init=zero'
463 endif
465 possible_cc_flags = [
466         '-fno-strict-aliasing',
467         '-fstrict-flex-arrays=1',
468         '-fvisibility=hidden',
471 if get_option('buildtype') != 'debug'
472         possible_cc_flags += [
473                 '-ffunction-sections',
474                 '-fdata-sections',
475         ]
477         possible_link_flags += '-Wl,--gc-sections'
478 endif
480 if get_option('mode') == 'developer'
481         possible_cc_flags += '-fno-omit-frame-pointer'
482 endif
484 add_project_arguments(
485         cc.get_supported_arguments(
486                 basic_disabled_warnings,
487                 possible_common_cc_flags
488         ),
489         language : 'c')
491 add_project_link_arguments(
492         cc.get_supported_link_arguments(possible_common_link_flags),
493         language : 'c')
495 userspace_c_args += cc.get_supported_arguments(possible_cc_flags)
496 userspace_c_ld_args += cc.get_supported_link_arguments(possible_link_flags)
498 have = cc.has_argument('-Wzero-length-bounds')
499 conf.set10('HAVE_ZERO_LENGTH_BOUNDS', have)
501 if cc.compiles('''
502    #include <time.h>
503    #include <inttypes.h>
504    typedef uint64_t usec_t;
505    usec_t now(clockid_t clock);
506    int main(void) {
507            struct timespec now;
508            return 0;
509    }
510 ''', args: '-Werror=shadow', name : '-Werror=shadow with local shadowing')
511         add_project_arguments('-Werror=shadow', language : 'c')
512 endif
514 if cxx_cmd != ''
515         add_project_arguments(cxx.get_supported_arguments(basic_disabled_warnings), language : 'cpp')
516 endif
518 cpp = ' '.join(cc.cmd_array() + get_option('c_args')) + ' -E'
520 has_wstringop_truncation = cc.has_argument('-Wstringop-truncation')
522 #####################################################################
523 # compilation result tests
525 conf.set('_GNU_SOURCE', 1)
526 conf.set('__SANE_USERSPACE_TYPES__', true)
527 conf.set10('HAVE_WSTRINGOP_TRUNCATION', has_wstringop_truncation)
529 conf.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include <sys/types.h>'))
530 conf.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include <sys/types.h>'))
531 conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
532 conf.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
533 conf.set('SIZEOF_TIMEX_MEMBER', cc.sizeof('typeof(((struct timex *)0)->freq)', prefix : '#include <sys/timex.h>'))
535 long_max = cc.compute_int(
536         'LONG_MAX',
537         prefix : '#include <limits.h>',
538         guess : 0x7FFFFFFFFFFFFFFF,
539         high : 0x7FFFFFFFFFFFFFFF)
540 assert(long_max > 100000)
541 conf.set_quoted('LONG_MAX_STR', '@0@'.format(long_max))
543 decl_headers = '''
544 #include <dirent.h>
545 #include <uchar.h>
546 #include <sys/mount.h>
547 #include <sys/stat.h>
550 foreach decl : ['char16_t',
551                 'char32_t',
552                 'struct mount_attr',
553                 'struct statx',
554                 'struct dirent64',
555                ]
557         # We get -1 if the size cannot be determined
558         have = cc.sizeof(decl, prefix : decl_headers, args : '-D_GNU_SOURCE') > 0
560         if decl == 'struct mount_attr'
561                 if have
562                         want_linux_fs_h = false
563                 else
564                         have = cc.sizeof(decl,
565                                          prefix : decl_headers + '#include <linux/fs.h>',
566                                          args : '-D_GNU_SOURCE') > 0
567                         want_linux_fs_h = have
568                 endif
569         endif
571         if decl == 'struct statx'
572                 if have
573                         want_linux_stat_h = false
574                 else
575                         have = cc.sizeof(decl,
576                                          prefix : decl_headers + '#include <linux/stat.h>',
577                                          args : '-D_GNU_SOURCE') > 0
578                         want_linux_stat_h = have
579                 endif
580         endif
582         conf.set10('HAVE_' + decl.underscorify().to_upper(), have)
583 endforeach
585 conf.set10('WANT_LINUX_STAT_H', want_linux_stat_h)
586 conf.set10('WANT_LINUX_FS_H', want_linux_fs_h)
588 foreach ident : ['secure_getenv', '__secure_getenv']
589         conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident))
590 endforeach
592 foreach ident : [
593         ['memfd_create',      '''#include <sys/mman.h>'''],
594         ['gettid',            '''#include <sys/types.h>
595                                  #include <unistd.h>'''],
596         ['fchmodat2',         '''#include <stdlib.h>
597                                  #include <fcntl.h>'''],      # no known header declares fchmodat2
598         ['pivot_root',        '''#include <stdlib.h>
599                                  #include <unistd.h>'''],     # no known header declares pivot_root
600         ['ioprio_get',        '''#include <sched.h>'''],      # no known header declares ioprio_get
601         ['ioprio_set',        '''#include <sched.h>'''],      # no known header declares ioprio_set
602         ['name_to_handle_at', '''#include <sys/types.h>
603                                  #include <sys/stat.h>
604                                  #include <fcntl.h>'''],
605         ['setns',             '''#include <sched.h>'''],
606         ['renameat2',         '''#include <stdio.h>
607                                  #include <fcntl.h>'''],
608         ['kcmp',              '''#include <linux/kcmp.h>'''],
609         ['keyctl',            '''#include <sys/types.h>
610                                  #include <keyutils.h>'''],
611         ['copy_file_range',   '''#include <sys/syscall.h>
612                                  #include <unistd.h>'''],
613         ['bpf',               '''#include <sys/syscall.h>
614                                  #include <unistd.h>'''],
615         ['statx',             '''#include <sys/types.h>
616                                  #include <sys/stat.h>
617                                  #include <unistd.h>'''],
618         ['explicit_bzero' ,   '''#include <string.h>'''],
619         ['reallocarray',      '''#include <stdlib.h>'''],
620         ['set_mempolicy',     '''#include <stdlib.h>
621                                  #include <unistd.h>'''],
622         ['get_mempolicy',     '''#include <stdlib.h>
623                                  #include <unistd.h>'''],
624         ['pidfd_send_signal', '''#include <stdlib.h>
625                                  #include <unistd.h>
626                                  #include <signal.h>
627                                  #include <sys/wait.h>'''],
628         ['pidfd_open',        '''#include <stdlib.h>
629                                  #include <unistd.h>
630                                  #include <signal.h>
631                                  #include <sys/wait.h>'''],
632         ['rt_sigqueueinfo',   '''#include <stdlib.h>
633                                  #include <unistd.h>
634                                  #include <signal.h>
635                                  #include <sys/wait.h>'''],
636         ['rt_tgsigqueueinfo', '''#include <stdlib.h>
637                                  #include <unistd.h>
638                                  #include <signal.h>
639                                  #include <sys/wait.h>'''],
640         ['mallinfo',          '''#include <malloc.h>'''],
641         ['mallinfo2',         '''#include <malloc.h>'''],
642         ['execveat',          '''#include <unistd.h>'''],
643         ['close_range',       '''#include <unistd.h>'''],
644         ['epoll_pwait2',      '''#include <sys/epoll.h>'''],
645         ['mount_setattr',     '''#include <sys/mount.h>'''],
646         ['move_mount',        '''#include <sys/mount.h>'''],
647         ['open_tree',         '''#include <sys/mount.h>'''],
648         ['fsopen',            '''#include <sys/mount.h>'''],
649         ['fsconfig',          '''#include <sys/mount.h>'''],
650         ['fsmount',           '''#include <sys/mount.h>'''],
651         ['getdents64',        '''#include <dirent.h>'''],
652         ['pidfd_spawn',       '''#include <spawn.h>'''],
655         have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
656         conf.set10('HAVE_' + ident[0].to_upper(), have)
657 endforeach
659 if cc.has_function('getrandom', prefix : '''#include <sys/random.h>''', args : '-D_GNU_SOURCE')
660         conf.set10('USE_SYS_RANDOM_H', true)
661         conf.set10('HAVE_GETRANDOM', true)
662 else
663         have = cc.has_function('getrandom', prefix : '''#include <linux/random.h>''')
664         conf.set10('USE_SYS_RANDOM_H', false)
665         conf.set10('HAVE_GETRANDOM', have)
666 endif
668 #####################################################################
670 sh = find_program('sh')
671 echo = find_program('echo')
672 sed = find_program('sed')
673 awk = find_program('awk')
674 stat = find_program('stat')
675 ln = find_program('ln')
676 git = find_program('git', required : false)
677 env = find_program('env')
678 rsync = find_program('rsync', required : false)
679 diff = find_program('diff')
680 find = find_program('find')
682 ln_s = ln.full_path() + ' -frsT -- "${DESTDIR:-}@0@" "${DESTDIR:-}@1@"'
684 # If -Dxxx-path option is found, use that. Otherwise, check in $PATH,
685 # /usr/sbin, /sbin, and fall back to the default from middle column.
686 progs = [['quotaon',    '/usr/sbin/quotaon'    ],
687          ['quotacheck', '/usr/sbin/quotacheck' ],
688          ['kmod',       '/usr/bin/kmod'        ],
689          ['kexec',      '/usr/sbin/kexec'      ],
690          ['sulogin',    '/usr/sbin/sulogin'    ],
691          ['mount',      '/usr/bin/mount',      'MOUNT_PATH'],
692          ['umount',     '/usr/bin/umount',     'UMOUNT_PATH'],
693          ['loadkeys',   '/usr/bin/loadkeys',   'KBD_LOADKEYS'],
694          ['setfont',    '/usr/bin/setfont',    'KBD_SETFONT'],
695          ['nologin',    '/usr/sbin/nologin',   ],
696         ]
697 foreach prog : progs
698         path = get_option(prog[0] + '-path')
699         if path != ''
700                 message('Using @1@ for @0@'.format(prog[0], path))
701         else
702                 exe = find_program(prog[0],
703                                    '/usr/sbin/' + prog[0],
704                                    '/sbin/' + prog[0],
705                                    required: false)
706                 path = exe.found() ? exe.full_path() : prog[1]
707         endif
708         name = prog.length() > 2 ? prog[2] : prog[0].to_upper()
709         conf.set_quoted(name, path)
710 endforeach
712 if run_command(ln, '--relative', '--help', check : false).returncode() != 0
713         error('ln does not support --relative (added in coreutils 8.16)')
714 endif
716 #####################################################################
718 gperf = find_program('gperf')
720 gperf_test_format = '''
721 #include <string.h>
722 const char * in_word_set(const char *, @0@);
725 gperf_snippet = run_command(sh, '-c', 'echo foo,bar | "$1" -L ANSI-C', '_', gperf,
726                             check : true)
727 gperf_test = gperf_test_format.format('size_t', gperf_snippet.stdout())
728 if cc.compiles(gperf_test)
729         gperf_len_type = 'size_t'
730 else
731         gperf_test = gperf_test_format.format('unsigned', gperf_snippet.stdout())
732         if cc.compiles(gperf_test)
733                 gperf_len_type = 'unsigned'
734         else
735                 error('unable to determine gperf len type')
736         endif
737 endif
738 message('gperf len type is @0@'.format(gperf_len_type))
739 conf.set('GPERF_LEN_TYPE', gperf_len_type,
740          description : 'The type of gperf "len" parameter')
742 #####################################################################
744 if not cc.has_header('sys/capability.h')
745         error('POSIX caps headers not found')
746 endif
747 foreach header : ['crypt.h',
748                   'linux/ioprio.h',
749                   'linux/memfd.h',
750                   'linux/time_types.h',
751                   'linux/vm_sockets.h',
752                   'sys/auxv.h',
753                   'sys/sdt.h',
754                   'threads.h',
755                   'valgrind/memcheck.h',
756                   'valgrind/valgrind.h',
757                  ]
759         conf.set10('HAVE_' + header.underscorify().to_upper(),
760                    cc.has_header(header))
761 endforeach
763 #####################################################################
765 fallback_hostname = get_option('fallback-hostname')
766 if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0] == '-'
767         error('Invalid fallback-hostname configuration')
768         # A more extensive test is done in test-hostname-util. Let's catch
769         # the most obvious errors here so we don't fail with an assert later.
770 endif
771 conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
773 extra_net_naming_schemes = []
774 extra_net_naming_map = []
775 foreach scheme: get_option('extra-net-naming-schemes').split(',')
776         if scheme != ''
777                 name = scheme.split('=')[0]
778                 value = scheme.split('=')[1]
779                 NAME = name.underscorify().to_upper()
780                 VALUE = []
781                 foreach field: value.split('+')
782                         VALUE += 'NAMING_' + field.underscorify().to_upper()
783                 endforeach
784                 extra_net_naming_schemes += 'NAMING_@0@ = @1@,'.format(NAME, '|'.join(VALUE))
785                 extra_net_naming_map += '{ "@0@", NAMING_@1@ },'.format(name, NAME)
786         endif
787 endforeach
788 conf.set('EXTRA_NET_NAMING_SCHEMES', ' '.join(extra_net_naming_schemes))
789 conf.set('EXTRA_NET_NAMING_MAP', ' '.join(extra_net_naming_map))
791 default_net_naming_scheme = get_option('default-net-naming-scheme')
792 conf.set_quoted('DEFAULT_NET_NAMING_SCHEME', default_net_naming_scheme,
793                 description : 'Default naming scheme as a string')
794 if default_net_naming_scheme != 'latest'
795         conf.set('_DEFAULT_NET_NAMING_SCHEME',
796                  'NAMING_' + default_net_naming_scheme.underscorify().to_upper(),
797                  description : 'Default naming scheme as a constant')
798 endif
800 time_epoch = get_option('time-epoch')
801 if time_epoch <= 0
802         time_epoch = run_command(sh, '-c', 'echo "$SOURCE_DATE_EPOCH"', check : true).stdout().strip()
803         if time_epoch == '' and git.found() and fs.is_dir('.git')
804                 # If we're in a git repository, use the creation time of the latest git tag.
805                 latest_tag = run_command(git, 'describe', '--abbrev=0', '--tags',
806                                          check : false)
807                 if latest_tag.returncode() == 0
808                         time_epoch = run_command(
809                                 git, 'log', '--no-show-signature', '-1', '--format=%at',
810                                      latest_tag.stdout().strip(),
811                                 check : false).stdout()
812                 endif
813         endif
814         if time_epoch == ''
815                 NEWS = files('NEWS')
816                 time_epoch = run_command(stat, '-c', '%Y', NEWS,
817                                          check : true).stdout()
818         endif
819         time_epoch = time_epoch.strip().to_int()
820 endif
821 conf.set('TIME_EPOCH', time_epoch)
823 conf.set('CLOCK_VALID_RANGE_USEC_MAX', get_option('clock-valid-range-usec-max'))
825 default_user_shell = get_option('default-user-shell')
826 conf.set_quoted('DEFAULT_USER_SHELL',      default_user_shell)
827 conf.set_quoted('DEFAULT_USER_SHELL_NAME', fs.name(default_user_shell))
829 foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1],  # Also see login.defs(5).
830                  ['system-uid-max',       'SYS_UID_MAX', 999],
831                  ['system-alloc-gid-min', 'SYS_GID_MIN', 1],
832                  ['system-gid-max',       'SYS_GID_MAX', 999]]
833         v = get_option(tuple[0])
834         if v <= 0
835                 v = run_command(
836                         awk,
837                         '/^\s*@0@\s+/ { uid=$2 } END { print uid }'.format(tuple[1]),
838                         '/etc/login.defs',
839                         check : false).stdout().strip()
840                 if v == ''
841                         v = tuple[2]
842                 else
843                         v = v.to_int()
844                 endif
845         endif
846         conf.set(tuple[0].underscorify().to_upper(), v)
847 endforeach
848 if conf.get('SYSTEM_ALLOC_UID_MIN') >= conf.get('SYSTEM_UID_MAX')
849         error('Invalid uid allocation range')
850 endif
851 if conf.get('SYSTEM_ALLOC_GID_MIN') >= conf.get('SYSTEM_GID_MAX')
852         error('Invalid gid allocation range')
853 endif
855 dynamic_uid_min = get_option('dynamic-uid-min')
856 dynamic_uid_max = get_option('dynamic-uid-max')
857 conf.set('DYNAMIC_UID_MIN', dynamic_uid_min)
858 conf.set('DYNAMIC_UID_MAX', dynamic_uid_max)
860 container_uid_base_min = get_option('container-uid-base-min')
861 container_uid_base_max = get_option('container-uid-base-max')
862 conf.set('CONTAINER_UID_BASE_MIN', container_uid_base_min)
863 conf.set('CONTAINER_UID_BASE_MAX', container_uid_base_max)
865 nobody_user = get_option('nobody-user')
866 nobody_group = get_option('nobody-group')
868 if not meson.is_cross_build()
869         getent_result = run_command('getent', 'passwd', '65534', check : false)
870         if getent_result.returncode() == 0
871                 name = getent_result.stdout().split(':')[0]
872                 if name != nobody_user
873                         warning('\n' +
874                                 'The local user with the UID 65534 does not match the configured user name "@0@" of the nobody user (its name is @1@).\n'.format(nobody_user, name) +
875                                 'Your build will result in an user table setup that is incompatible with the local system.')
876                 endif
877         endif
878         id_result = run_command('id', '-u', nobody_user, check : false)
879         if id_result.returncode() == 0
880                 id = id_result.stdout().strip().to_int()
881                 if id != 65534
882                         warning('\n' +
883                                 'The local user with the configured user name "@0@" of the nobody user does not have UID 65534 (it has @1@).\n'.format(nobody_user, id) +
884                                 'Your build will result in an user table setup that is incompatible with the local system.')
885                 endif
886         endif
888         getent_result = run_command('getent', 'group', '65534', check : false)
889         if getent_result.returncode() == 0
890                 name = getent_result.stdout().split(':')[0]
891                 if name != nobody_group
892                         warning('\n' +
893                                 'The local group with the GID 65534 does not match the configured group name "@0@" of the nobody group (its name is @1@).\n'.format(nobody_group, name) +
894                                 'Your build will result in an group table setup that is incompatible with the local system.')
895                 endif
896         endif
897         id_result = run_command('id', '-g', nobody_group, check : false)
898         if id_result.returncode() == 0
899                 id = id_result.stdout().strip().to_int()
900                 if id != 65534
901                         warning('\n' +
902                                 'The local group with the configured group name "@0@" of the nobody group does not have GID 65534 (it has @1@).\n'.format(nobody_group, id) +
903                                 'Your build will result in an group table setup that is incompatible with the local system.')
904                 endif
905         endif
906 endif
907 if nobody_user != nobody_group and not (nobody_user == 'nobody' and nobody_group == 'nogroup')
908         warning('\n' +
909                 'The configured user name "@0@" and group name "@1@" of the nobody user/group are not equivalent.\n'.format(nobody_user, nobody_group) +
910                 'Please re-check that both "nobody-user" and "nobody-group" options are correctly set.')
911 endif
913 conf.set_quoted('NOBODY_USER_NAME', nobody_user)
914 conf.set_quoted('NOBODY_GROUP_NAME', nobody_group)
916 static_ugids = []
917 foreach option : ['adm-gid',
918                   'audio-gid',
919                   'cdrom-gid',
920                   'dialout-gid',
921                   'disk-gid',
922                   'input-gid',
923                   'kmem-gid',
924                   'kvm-gid',
925                   'lp-gid',
926                   'render-gid',
927                   'sgx-gid',
928                   'tape-gid',
929                   'tty-gid',
930                   'users-gid',
931                   'utmp-gid',
932                   'video-gid',
933                   'wheel-gid',
934                   'systemd-journal-gid',
935                   'systemd-network-uid',
936                   'systemd-resolve-uid',
937                   'systemd-timesync-uid']
938         name = option.underscorify().to_upper()
939         val = get_option(option)
941         # Ensure provided GID argument is numeric, otherwise fall back to default assignment
942         conf.set(name, val > 0 ? val : '-')
943         if val > 0
944                 static_ugids += '@0@:@1@'.format(option, val)
945         endif
946 endforeach
948 conf.set10('ENABLE_ADM_GROUP', get_option('adm-group'))
949 conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group'))
951 dev_kvm_mode = get_option('dev-kvm-mode')
952 conf.set_quoted('DEV_KVM_MODE', dev_kvm_mode) # FIXME: convert to 0o… notation
953 conf.set10('DEV_KVM_UACCESS', dev_kvm_mode != '0666')
954 group_render_mode = get_option('group-render-mode')
955 conf.set_quoted('GROUP_RENDER_MODE', group_render_mode)
956 conf.set10('GROUP_RENDER_UACCESS', group_render_mode != '0666')
958 kill_user_processes = get_option('default-kill-user-processes')
959 conf.set10('KILL_USER_PROCESSES', kill_user_processes)
961 dns_servers = get_option('dns-servers')
962 conf.set_quoted('DNS_SERVERS', dns_servers)
964 ntp_servers = get_option('ntp-servers')
965 conf.set_quoted('NTP_SERVERS', ntp_servers)
967 default_locale = get_option('default-locale')
968 conf.set_quoted('SYSTEMD_DEFAULT_LOCALE', default_locale)
970 nspawn_locale = get_option('nspawn-locale')
971 conf.set_quoted('SYSTEMD_NSPAWN_LOCALE', nspawn_locale)
973 default_keymap = get_option('default-keymap')
974 if default_keymap == ''
975         # We canonicalize empty keymap to '@kernel', as it makes the default value
976         # in the factory provided /etc/vconsole.conf more obvious.
977         default_keymap = '@kernel'
978 endif
979 conf.set_quoted('SYSTEMD_DEFAULT_KEYMAP', default_keymap)
981 localegen_path = get_option('localegen-path')
982 if localegen_path != ''
983         conf.set_quoted('LOCALEGEN_PATH', localegen_path)
984 endif
985 conf.set10('HAVE_LOCALEGEN', localegen_path != '')
987 conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
989 service_watchdog = get_option('service-watchdog')
990 watchdog_value = service_watchdog == '' ? '' : 'WatchdogSec=' + service_watchdog
991 conf.set_quoted('SERVICE_WATCHDOG', watchdog_value)
993 conf.set_quoted('SUSHELL', get_option('debug-shell'))
994 conf.set_quoted('DEBUGTTY', get_option('debug-tty'))
996 enable_debug_hashmap = false
997 enable_debug_mmap_cache = false
998 enable_debug_siphash = false
999 foreach name : get_option('debug-extra')
1000         if name == 'hashmap'
1001                 enable_debug_hashmap = true
1002         elif name == 'mmap-cache'
1003                 enable_debug_mmap_cache = true
1004         elif name == 'siphash'
1005                 enable_debug_siphash = true
1006         else
1007                 message('unknown debug option "@0@", ignoring'.format(name))
1008         endif
1009 endforeach
1010 conf.set10('ENABLE_DEBUG_HASHMAP', enable_debug_hashmap)
1011 conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache)
1012 conf.set10('ENABLE_DEBUG_SIPHASH', enable_debug_siphash)
1013 conf.set10('LOG_TRACE', get_option('log-trace'))
1015 default_user_path = get_option('user-path')
1016 if default_user_path != ''
1017         conf.set_quoted('DEFAULT_USER_PATH', default_user_path)
1018 endif
1020 #####################################################################
1022 threads = dependency('threads')
1023 librt = cc.find_library('rt')
1024 libm = cc.find_library('m')
1025 libdl = cc.find_library('dl')
1026 libcrypt = dependency('libcrypt', 'libxcrypt', required : false)
1027 if not libcrypt.found()
1028         # fallback to use find_library() if libcrypt is provided by glibc, e.g. for LibreELEC.
1029         libcrypt = cc.find_library('crypt')
1030 endif
1031 libcap = dependency('libcap')
1033 # On some architectures, libatomic is required. But on some installations,
1034 # it is found, but actual linking fails. So let's try to use it opportunistically.
1035 # If it is installed, but not needed, it will be dropped because of --as-needed.
1036 if cc.links('''int main(int argc, char **argv) { return 0; }''',
1037             args : '-latomic',
1038             name : 'libatomic')
1039         libatomic = declare_dependency(link_args : '-latomic')
1040 else
1041         libatomic = []
1042 endif
1044 crypt_header = conf.get('HAVE_CRYPT_H') == 1 ? '''#include <crypt.h>''' : '''#include <unistd.h>'''
1045 foreach ident : [
1046         ['crypt_ra',               crypt_header],
1047         ['crypt_preferred_method', crypt_header],
1048         ['crypt_gensalt_ra',       crypt_header]]
1050         have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE',
1051                                dependencies : libcrypt)
1052         conf.set10('HAVE_' + ident[0].to_upper(), have)
1053 endforeach
1055 bpf_framework = get_option('bpf-framework')
1056 bpf_compiler = get_option('bpf-compiler')
1057 libbpf = dependency('libbpf',
1058                     required : bpf_framework,
1059                     version : bpf_compiler == 'gcc' ? '>= 1.0.0' : '>= 0.1.0')
1060 conf.set10('HAVE_LIBBPF', libbpf.found())
1062 if not libbpf.found()
1063         conf.set10('BPF_FRAMEWORK', false)
1064 else
1065         clang_found = false
1066         clang_supports_bpf = false
1067         bpf_gcc_found = false
1068         bpftool_strip = false
1069         deps_found = false
1071         if bpf_compiler == 'clang'
1072                 # Support 'versioned' clang/llvm-strip binaries, as seen on Debian/Ubuntu
1073                 # (like clang-10/llvm-strip-10)
1074                 if meson.is_cross_build() or cc.get_id() != 'clang' or cc.cmd_array()[0].contains('afl-clang') or cc.cmd_array()[0].contains('hfuzz-clang')
1075                         r = find_program('clang',
1076                                          required : bpf_framework,
1077                                          version : '>= 10.0.0')
1078                         clang_found = r.found()
1079                         if clang_found
1080                                 clang = r.full_path()
1081                         endif
1082                 else
1083                         clang_found = true
1084                         clang = cc.cmd_array()
1085                 endif
1087                 if clang_found
1088                         # Check if 'clang -target bpf' is supported.
1089                         clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus', check : false).returncode() == 0
1090                 endif
1091         elif bpf_compiler == 'gcc'
1092                 bpf_gcc = find_program('bpf-gcc',
1093                                        'bpf-none-gcc',
1094                                        required : true,
1095                                        version : '>= 13.1.0')
1096                 bpf_gcc_found = bpf_gcc.found()
1097         endif
1099         if clang_supports_bpf or bpf_gcc_found
1100                 # Debian installs this in /usr/sbin/ which is not in $PATH.
1101                 # We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian.
1102                 # We use 'bpftool gen object' subcommand for bpftool strip, it was added by d80b2fcbe0a023619e0fc73112f2a02c2662f6ab (v5.13).
1103                 bpftool = find_program('bpftool',
1104                                        '/usr/sbin/bpftool',
1105                                        required : bpf_framework.enabled() and bpf_compiler == 'gcc',
1106                                        version : bpf_compiler == 'gcc' ? '>= 7.0.0' : '>= 5.13.0')
1108                 if bpftool.found()
1109                         bpftool_strip = true
1110                         deps_found = true
1111                 elif bpf_compiler == 'clang'
1112                         # We require the 'bpftool gen skeleton' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6).
1113                         bpftool = find_program('bpftool',
1114                                                '/usr/sbin/bpftool',
1115                                                required : bpf_framework,
1116                                                version : '>= 5.6.0')
1117                 endif
1119                 # We use `llvm-strip` as a fallback if `bpftool gen object` strip support is not available.
1120                 if not bpftool_strip and bpftool.found() and clang_supports_bpf
1121                         if not meson.is_cross_build()
1122                                 llvm_strip_bin = run_command(clang, '--print-prog-name', 'llvm-strip',
1123                                                              check : true).stdout().strip()
1124                         else
1125                                 llvm_strip_bin = 'llvm-strip'
1126                         endif
1127                         llvm_strip = find_program(llvm_strip_bin,
1128                                                   required : bpf_framework,
1129                                                   version : '>= 10.0.0')
1130                         deps_found = llvm_strip.found()
1131                 endif
1132         endif
1134         # Can build BPF program from source code in restricted C
1135         conf.set10('BPF_FRAMEWORK', deps_found)
1136 endif
1138 libmount = dependency('mount',
1139                       version : fuzzer_build ? '>= 0' : '>= 2.30')
1141 libfdisk = dependency('fdisk',
1142                       version : '>= 2.32',
1143                       disabler : true,
1144                       required : get_option('fdisk'))
1145 conf.set10('HAVE_LIBFDISK', libfdisk.found())
1147 # This prefers pwquality if both are enabled or auto.
1148 feature = get_option('pwquality').disable_auto_if(get_option('passwdqc').enabled())
1149 libpwquality = dependency('pwquality',
1150                           version : '>= 1.4.1',
1151                           required : feature)
1152 have = libpwquality.found()
1153 if not have
1154         # libpwquality is used for both features for simplicity
1155         libpwquality = dependency('passwdqc',
1156                                   required : get_option('passwdqc'))
1157 endif
1158 conf.set10('HAVE_PWQUALITY', have)
1159 conf.set10('HAVE_PASSWDQC', not have and libpwquality.found())
1161 libseccomp = dependency('libseccomp',
1162                         version : '>= 2.3.1',
1163                         required : get_option('seccomp'))
1164 conf.set10('HAVE_SECCOMP', libseccomp.found())
1166 libselinux = dependency('libselinux',
1167                         version : '>= 2.1.9',
1168                         required : get_option('selinux'))
1169 conf.set10('HAVE_SELINUX', libselinux.found())
1171 libapparmor = dependency('libapparmor',
1172                          version : '>= 2.13',
1173                          required : get_option('apparmor'))
1174 conf.set10('HAVE_APPARMOR', libapparmor.found())
1176 have = get_option('smack') and get_option('smack-run-label') != ''
1177 conf.set10('HAVE_SMACK_RUN_LABEL', have)
1178 if have
1179         conf.set_quoted('SMACK_RUN_LABEL', get_option('smack-run-label'))
1180 endif
1182 have = get_option('smack') and get_option('smack-default-process-label') != ''
1183 if have
1184         conf.set_quoted('SMACK_DEFAULT_PROCESS_LABEL', get_option('smack-default-process-label'))
1185 endif
1187 feature = get_option('polkit')
1188 libpolkit = dependency('polkit-gobject-1',
1189                        required : feature.disabled() ? feature : false)
1190 install_polkit = feature.allowed()
1191 install_polkit_pkla = libpolkit.found() and libpolkit.version().version_compare('< 0.106')
1192 if install_polkit_pkla
1193         message('Old polkit detected, will install pkla files')
1194 endif
1195 conf.set10('ENABLE_POLKIT', install_polkit)
1197 libacl = dependency('libacl',
1198                     required : get_option('acl'))
1199 conf.set10('HAVE_ACL', libacl.found())
1201 libaudit = dependency('audit',
1202                       required : get_option('audit'))
1203 conf.set10('HAVE_AUDIT', libaudit.found())
1205 libblkid = dependency('blkid',
1206                       required : get_option('blkid'))
1207 conf.set10('HAVE_BLKID', libblkid.found())
1208 conf.set10('HAVE_BLKID_PROBE_SET_HINT',
1209            libblkid.found() and cc.has_function('blkid_probe_set_hint', dependencies : libblkid))
1211 libkmod = dependency('libkmod',
1212                      version : '>= 15',
1213                      required : get_option('kmod'))
1214 conf.set10('HAVE_KMOD', libkmod.found())
1215 libkmod_cflags = libkmod.partial_dependency(includes: true, compile_args: true)
1217 libxenctrl = dependency('xencontrol',
1218                         version : '>= 4.9',
1219                         required : get_option('xenctrl'))
1220 conf.set10('HAVE_XENCTRL', libxenctrl.found())
1221 libxenctrl_cflags = libxenctrl.partial_dependency(includes: true, compile_args: true)
1223 feature = get_option('pam')
1224 libpam = dependency('pam',
1225                     required : feature.disabled() ? feature : false)
1226 if not libpam.found()
1227         # Debian older than bookworm and Ubuntu older than 22.10 do not provide the .pc file.
1228         libpam = cc.find_library('pam', required : feature)
1229 endif
1230 libpam_misc = dependency('pam_misc',
1231                          required : feature.disabled() ? feature : false)
1232 if not libpam_misc.found()
1233         libpam_misc = cc.find_library('pam_misc', required : feature)
1234 endif
1235 conf.set10('HAVE_PAM', libpam.found() and libpam_misc.found())
1237 libmicrohttpd = dependency('libmicrohttpd',
1238                            version : '>= 0.9.33',
1239                            required : get_option('microhttpd'))
1240 conf.set10('HAVE_MICROHTTPD', libmicrohttpd.found())
1242 libcryptsetup = get_option('libcryptsetup')
1243 libcryptsetup_plugins = get_option('libcryptsetup-plugins')
1244 if libcryptsetup_plugins.enabled()
1245         if libcryptsetup.disabled()
1246                 error('libcryptsetup-plugins cannot be requested without libcryptsetup')
1247         endif
1248         libcryptsetup = libcryptsetup_plugins
1249 endif
1251 libcryptsetup = dependency('libcryptsetup',
1252                            version : libcryptsetup_plugins.enabled() ? '>= 2.4.0' : '>= 2.0.1',
1253                            required : libcryptsetup)
1255 have = libcryptsetup.found()
1256 foreach ident : ['crypt_set_metadata_size',
1257                  'crypt_activate_by_signed_key',
1258                  'crypt_token_max',
1259                  'crypt_reencrypt_init_by_passphrase',
1260                  'crypt_reencrypt',
1261                  'crypt_set_data_offset',
1262                  'crypt_set_keyring_to_link',
1263                  'crypt_resume_by_volume_key']
1264         have_ident = have and cc.has_function(
1265                 ident,
1266                 prefix : '#include <libcryptsetup.h>',
1267                 dependencies : libcryptsetup)
1268         conf.set10('HAVE_' + ident.to_upper(), have_ident)
1269 endforeach
1270 conf.set10('HAVE_LIBCRYPTSETUP', have)
1272 # TODO: Use has_function(required : libcryptsetup_plugins) with meson >= 1.3.0
1273 if libcryptsetup_plugins.allowed()
1274         have = (cc.has_function(
1275                         'crypt_activate_by_token_pin',
1276                         prefix : '#include <libcryptsetup.h>',
1277                         dependencies : libcryptsetup) and
1278                 cc.has_function(
1279                         'crypt_token_external_path',
1280                         prefix : '#include <libcryptsetup.h>',
1281                         dependencies : libcryptsetup))
1282 else
1283         have = false
1284 endif
1285 conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS', have)
1287 libcurl = dependency('libcurl',
1288                      version : '>= 7.32.0',
1289                      required : get_option('libcurl'))
1290 conf.set10('HAVE_LIBCURL', libcurl.found())
1291 conf.set10('CURL_NO_OLDIES', conf.get('BUILD_MODE_DEVELOPER') == 1)
1293 feature = get_option('libidn2').disable_auto_if(get_option('libidn').enabled())
1294 libidn = dependency('libidn2',
1295                     required : feature)
1296 have = libidn.found()
1297 if not have
1298         # libidn is used for both libidn and libidn2 objects
1299         libidn = dependency('libidn',
1300                             required : get_option('libidn'))
1301 endif
1302 conf.set10('HAVE_LIBIDN', not have and libidn.found())
1303 conf.set10('HAVE_LIBIDN2', have)
1305 libiptc = dependency('libiptc',
1306                      required : get_option('libiptc'))
1307 conf.set10('HAVE_LIBIPTC', libiptc.found())
1308 libiptc_cflags = libiptc.partial_dependency(includes: true, compile_args: true)
1310 libqrencode = dependency('libqrencode',
1311                          version : '>= 3',
1312                          required : get_option('qrencode'))
1313 conf.set10('HAVE_QRENCODE', libqrencode.found())
1315 feature = get_option('gcrypt')
1316 libgcrypt = dependency('libgcrypt',
1317                        required : feature)
1318 libgpg_error = dependency('gpg-error',
1319                           required : feature.disabled() ? feature : false)
1320 if not libgpg_error.found()
1321         # CentOS 8 does not provide the .pc file.
1322         libgpg_error = cc.find_library('gpg-error', required : feature)
1323 endif
1325 have = libgcrypt.found() and libgpg_error.found()
1326 if not have
1327         # link to neither of the libs if one is not found
1328         libgcrypt = []
1329         libgpg_error = []
1330         libgcrypt_cflags = []
1331 else
1332         libgcrypt_cflags = libgcrypt.partial_dependency(includes: true, compile_args: true)
1333 endif
1334 conf.set10('HAVE_GCRYPT', have)
1336 libgnutls = dependency('gnutls',
1337                        version : '>= 3.1.4',
1338                        required : get_option('gnutls'))
1339 conf.set10('HAVE_GNUTLS', libgnutls.found())
1341 libopenssl = dependency('openssl',
1342                         version : '>= 1.1.0',
1343                         required : get_option('openssl'))
1344 conf.set10('HAVE_OPENSSL', libopenssl.found())
1346 libp11kit = dependency('p11-kit-1',
1347                        version : '>= 0.23.3',
1348                        required : get_option('p11kit'))
1349 conf.set10('HAVE_P11KIT', libp11kit.found())
1350 libp11kit_cflags = libp11kit.partial_dependency(includes: true, compile_args: true)
1352 feature = get_option('libfido2').require(
1353         conf.get('HAVE_OPENSSL') == 1,
1354         error_message : 'openssl required')
1355 libfido2 = dependency('libfido2',
1356                       required : feature)
1357 conf.set10('HAVE_LIBFIDO2', libfido2.found())
1359 tpm2 = dependency('tss2-esys tss2-rc tss2-mu tss2-tcti-device',
1360                   required : get_option('tpm2'))
1361 conf.set10('HAVE_TPM2', tpm2.found())
1362 conf.set10('HAVE_TSS2_ESYS3', tpm2.found() and tpm2.version().version_compare('>= 3.0.0'))
1364 libdw = dependency('libdw',
1365                    required : get_option('elfutils'))
1366 conf.set10('HAVE_ELFUTILS', libdw.found())
1367 # New in elfutils 0.177
1368 conf.set10('HAVE_DWELF_ELF_E_MACHINE_STRING',
1369            libdw.found() and cc.has_function('dwelf_elf_e_machine_string', dependencies : libdw))
1371 libz = dependency('zlib',
1372                   required : get_option('zlib'))
1373 conf.set10('HAVE_ZLIB', libz.found())
1375 feature = get_option('bzip2')
1376 libbzip2 = dependency('bzip2',
1377                       required : feature.disabled() ? feature : false)
1378 if not libbzip2.found()
1379         # Debian and Ubuntu do not provide the .pc file.
1380         libbzip2 = cc.find_library('bz2', required : feature)
1381 endif
1382 conf.set10('HAVE_BZIP2', libbzip2.found())
1384 libxz = dependency('liblzma',
1385                    required : get_option('xz'))
1386 conf.set10('HAVE_XZ', libxz.found())
1387 libxz_cflags = libxz.partial_dependency(includes: true, compile_args: true)
1389 liblz4 = dependency('liblz4',
1390                     version : '>= 1.3.0',
1391                     required : get_option('lz4'))
1392 conf.set10('HAVE_LZ4', liblz4.found())
1393 liblz4_cflags = liblz4.partial_dependency(includes: true, compile_args: true)
1395 libzstd = dependency('libzstd',
1396                      version : '>= 1.4.0',
1397                      required : get_option('zstd'))
1398 conf.set10('HAVE_ZSTD', libzstd.found())
1399 libzstd_cflags = libzstd.partial_dependency(includes: true, compile_args: true)
1401 conf.set10('HAVE_COMPRESSION', libxz.found() or liblz4.found() or libzstd.found())
1403 compression = get_option('default-compression')
1404 if compression == 'auto'
1405         if libzstd.found()
1406                 compression = 'zstd'
1407         elif liblz4.found()
1408                 compression = 'lz4'
1409         elif libxz.found()
1410                 compression = 'xz'
1411         else
1412                 compression = 'none'
1413         endif
1414 elif compression == 'zstd' and not libzstd.found()
1415         error('default-compression=zstd requires zstd')
1416 elif compression == 'lz4' and not liblz4.found()
1417         error('default-compression=lz4 requires lz4')
1418 elif compression == 'xz' and not libxz.found()
1419         error('default-compression=xz requires xz')
1420 endif
1421 conf.set('DEFAULT_COMPRESSION', 'COMPRESSION_@0@'.format(compression.to_upper()))
1423 libarchive = dependency('libarchive',
1424                         version : '>= 3.0',
1425                         required : get_option('libarchive'))
1426 conf.set10('HAVE_LIBARCHIVE', libarchive.found())
1428 libxkbcommon = dependency('xkbcommon',
1429                           version : '>= 0.3.0',
1430                           required : get_option('xkbcommon'))
1431 conf.set10('HAVE_XKBCOMMON', libxkbcommon.found())
1433 libpcre2 = dependency('libpcre2-8',
1434                       required : get_option('pcre2'))
1435 conf.set10('HAVE_PCRE2', libpcre2.found())
1437 libglib =    dependency('glib-2.0',
1438                         version : '>= 2.22.0',
1439                         required : get_option('glib'))
1440 libgobject = dependency('gobject-2.0',
1441                         version : '>= 2.22.0',
1442                         required : get_option('glib'))
1443 libgio =     dependency('gio-2.0',
1444                         required : get_option('glib'))
1445 conf.set10('HAVE_GLIB', libglib.found() and libgobject.found() and libgio.found())
1447 libdbus = dependency('dbus-1',
1448                      version : '>= 1.3.2',
1449                      required : get_option('dbus'))
1450 conf.set10('HAVE_DBUS', libdbus.found())
1452 dbusdatadir = libdbus.get_variable(pkgconfig: 'datadir', default_value: datadir) / 'dbus-1'
1454 dbuspolicydir = get_option('dbuspolicydir')
1455 if dbuspolicydir == ''
1456         dbuspolicydir = dbusdatadir / 'system.d'
1457 endif
1459 dbussessionservicedir = get_option('dbussessionservicedir')
1460 if dbussessionservicedir == ''
1461         dbussessionservicedir = libdbus.get_variable(pkgconfig: 'session_bus_services_dir', default_value: dbusdatadir / 'services')
1462 endif
1464 dbussystemservicedir = get_option('dbussystemservicedir')
1465 if dbussystemservicedir == ''
1466         dbussystemservicedir = libdbus.get_variable(pkgconfig: 'system_bus_services_dir', default_value: dbusdatadir / 'system-services')
1467 endif
1469 dbus_interfaces_dir = get_option('dbus-interfaces-dir')
1470 if dbus_interfaces_dir == '' or dbus_interfaces_dir == 'yes'
1471         if meson.is_cross_build() and dbus_interfaces_dir != 'yes'
1472                 dbus_interfaces_dir = 'no'
1473                 warning('Exporting D-Bus interface XML files is disabled during cross build. Pass path or "yes" to force enable.')
1474         else
1475                 dbus_interfaces_dir = libdbus.get_variable(pkgconfig: 'interfaces_dir', default_value: dbusdatadir / 'interfaces')
1476         endif
1477 endif
1479 dmi_arches = ['x86', 'x86_64', 'aarch64', 'arm', 'ia64', 'loongarch64', 'mips']
1480 conf.set10('HAVE_DMI', host_machine.cpu_family() in dmi_arches)
1482 # We support one or the other. If gcrypt is available, we assume it's there to
1483 # be used, and use it in preference.
1484 opt = get_option('cryptolib')
1485 if opt == 'openssl' and conf.get('HAVE_OPENSSL') == 0
1486         error('openssl requested as the default cryptolib, but not available')
1487 endif
1488 conf.set10('PREFER_OPENSSL',
1489            opt == 'openssl' or (opt == 'auto' and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_GCRYPT') == 0))
1490 conf.set10('HAVE_OPENSSL_OR_GCRYPT',
1491            conf.get('HAVE_OPENSSL') == 1 or conf.get('HAVE_GCRYPT') == 1)
1492 lib_openssl_or_gcrypt = conf.get('PREFER_OPENSSL') == 1 ? [libopenssl] : [libgcrypt, libgpg_error]
1494 dns_over_tls = get_option('dns-over-tls')
1495 if dns_over_tls != 'false'
1496         if dns_over_tls == 'gnutls' and conf.get('PREFER_OPENSSL') == 1
1497                 error('Sorry, -Ddns-over-tls=gnutls is not supported when openssl is used as the cryptolib')
1498         endif
1500         if dns_over_tls == 'gnutls'
1501                 have_openssl = false
1502         else
1503                 have_openssl = conf.get('HAVE_OPENSSL') == 1
1504                 if dns_over_tls == 'openssl' and not have_openssl
1505                         error('DNS-over-TLS support was requested with openssl, but dependencies are not available')
1506                 endif
1507         endif
1508         if dns_over_tls == 'openssl' or have_openssl
1509                 have_gnutls = false
1510         else
1511                 have_gnutls = conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.6.0')
1512                 if dns_over_tls != 'auto' and not have_gnutls
1513                         str = dns_over_tls == 'gnutls' ? ' with gnutls' : ''
1514                         error('DNS-over-TLS support was requested@0@, but dependencies are not available'.format(str))
1515                 endif
1516         endif
1517         have = have_gnutls or have_openssl
1518 else
1519         have = false
1520         have_gnutls = false
1521         have_openssl = false
1522 endif
1523 conf.set10('ENABLE_DNS_OVER_TLS', have)
1524 conf.set10('DNS_OVER_TLS_USE_GNUTLS', have_gnutls)
1525 conf.set10('DNS_OVER_TLS_USE_OPENSSL', have_openssl)
1527 default_dns_over_tls = get_option('default-dns-over-tls')
1528 if default_dns_over_tls != 'no' and conf.get('ENABLE_DNS_OVER_TLS') == 0
1529         message('default-dns-over-tls cannot be enabled or set to opportunistic when DNS-over-TLS support is disabled. Setting default-dns-over-tls to no.')
1530         default_dns_over_tls = 'no'
1531 endif
1532 conf.set('DEFAULT_DNS_OVER_TLS_MODE',
1533          'DNS_OVER_TLS_' + default_dns_over_tls.underscorify().to_upper())
1534 conf.set_quoted('DEFAULT_DNS_OVER_TLS_MODE_STR', default_dns_over_tls)
1536 default_mdns = get_option('default-mdns')
1537 conf.set('DEFAULT_MDNS_MODE',
1538          'RESOLVE_SUPPORT_' + default_mdns.to_upper())
1539 conf.set_quoted('DEFAULT_MDNS_MODE_STR', default_mdns)
1541 default_llmnr = get_option('default-llmnr')
1542 conf.set('DEFAULT_LLMNR_MODE',
1543          'RESOLVE_SUPPORT_' + default_llmnr.to_upper())
1544 conf.set_quoted('DEFAULT_LLMNR_MODE_STR', default_llmnr)
1546 have = get_option('repart').require(
1547         conf.get('HAVE_LIBFDISK') == 1,
1548         error_message : 'fdisk required').allowed()
1549 conf.set10('ENABLE_REPART', have)
1551 default_dnssec = get_option('default-dnssec')
1552 if default_dnssec != 'no' and conf.get('HAVE_OPENSSL_OR_GCRYPT') == 0
1553         message('default-dnssec cannot be set to yes or allow-downgrade openssl and gcrypt are disabled. Setting default-dnssec to no.')
1554         default_dnssec = 'no'
1555 endif
1556 conf.set('DEFAULT_DNSSEC_MODE',
1557          'DNSSEC_' + default_dnssec.underscorify().to_upper())
1558 conf.set_quoted('DEFAULT_DNSSEC_MODE_STR', default_dnssec)
1560 have = get_option('sysupdate').require(
1561         conf.get('HAVE_OPENSSL') == 1 and
1562         conf.get('HAVE_LIBFDISK') == 1,
1563         error_message : 'fdisk and openssl required').allowed()
1564 conf.set10('ENABLE_SYSUPDATE', have)
1566 conf.set10('ENABLE_STORAGETM', get_option('storagetm'))
1568 have = get_option('importd').require(
1569         conf.get('HAVE_LIBCURL') == 1 and
1570         conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and
1571         conf.get('HAVE_ZLIB') == 1 and
1572         conf.get('HAVE_XZ') == 1,
1573         error_message : 'curl, openssl/grypt, zlib and xz required').allowed()
1574 conf.set10('ENABLE_IMPORTD', have)
1576 have = get_option('homed').require(
1577         conf.get('HAVE_OPENSSL') == 1 and
1578         conf.get('HAVE_LIBFDISK') == 1 and
1579         conf.get('HAVE_LIBCRYPTSETUP') == 1 and
1580         conf.get('HAVE_CRYPT_RESUME_BY_VOLUME_KEY') == 1,
1581         error_message : 'openssl, fdisk and libcryptsetup required').allowed()
1582 conf.set10('ENABLE_HOMED', have)
1584 have = have and conf.get('HAVE_PAM') == 1
1585 conf.set10('ENABLE_PAM_HOME', have)
1587 feature = get_option('remote')
1588 have_deps = [conf.get('HAVE_MICROHTTPD') == 1,
1589              conf.get('HAVE_LIBCURL') == 1]
1590 # sd-j-remote requires µhttpd, and sd-j-upload requires libcurl, so
1591 # it's possible to build one without the other. Complain only if
1592 # support was explicitly requested. The auxiliary files like sysusers
1593 # config should be installed when any of the programs are built.
1594 if feature.enabled() and not (have_deps[0] and have_deps[1])
1595         error('remote support was requested, but dependencies are not available')
1596 endif
1597 have = feature.allowed() and (have_deps[0] or have_deps[1])
1598 conf.set10('ENABLE_REMOTE', have)
1600 feature = get_option('vmspawn').disable_auto_if(conf.get('BUILD_MODE_DEVELOPER') == 0)
1601 conf.set10('ENABLE_VMSPAWN', feature.allowed())
1603 conf.set10('DEFAULT_MOUNTFSD_TRUSTED_DIRECTORIES', get_option('default-mountfsd-trusted-directories'))
1605 foreach term : ['analyze',
1606                 'backlight',
1607                 'binfmt',
1608                 'compat-mutable-uid-boundaries',
1609                 'coredump',
1610                 'efi',
1611                 'environment-d',
1612                 'firstboot',
1613                 'gshadow',
1614                 'hibernate',
1615                 'hostnamed',
1616                 'hwdb',
1617                 'idn',
1618                 'ima',
1619                 'initrd',
1620                 'kernel-install',
1621                 'ldconfig',
1622                 'localed',
1623                 'logind',
1624                 'machined',
1625                 'mountfsd',
1626                 'networkd',
1627                 'nscd',
1628                 'nsresourced',
1629                 'nss-myhostname',
1630                 'nss-systemd',
1631                 'oomd',
1632                 'portabled',
1633                 'pstore',
1634                 'quotacheck',
1635                 'randomseed',
1636                 'resolve',
1637                 'rfkill',
1638                 'smack',
1639                 'sysext',
1640                 'sysusers',
1641                 'timedated',
1642                 'timesyncd',
1643                 'tmpfiles',
1644                 'tpm',
1645                 'userdb',
1646                 'utmp',
1647                 'vconsole',
1648                 'xdg-autostart']
1649         have = get_option(term)
1650         name = 'ENABLE_' + term.underscorify().to_upper()
1651         conf.set10(name, have)
1652 endforeach
1654 enable_sysusers = conf.get('ENABLE_SYSUSERS') == 1
1656 foreach tuple : [['nss-mymachines', 'machined'],
1657                  ['nss-resolve',    'resolve']]
1658         want = get_option(tuple[0])
1659         if want.allowed()
1660                 have = get_option(tuple[1])
1661                 if want.enabled() and not have
1662                         error('@0@ is requested but @1@ is disabled'.format(tuple[0], tuple[1]))
1663                 endif
1664         else
1665                 have = false
1666         endif
1667         name = 'ENABLE_' + tuple[0].underscorify().to_upper()
1668         conf.set10(name, have)
1669 endforeach
1671 enable_nss = false
1672 foreach term : ['ENABLE_NSS_MYHOSTNAME',
1673                 'ENABLE_NSS_MYMACHINES',
1674                 'ENABLE_NSS_RESOLVE',
1675                 'ENABLE_NSS_SYSTEMD']
1676         if conf.get(term) == 1
1677                 enable_nss = true
1678         endif
1679 endforeach
1680 conf.set10('ENABLE_NSS', enable_nss)
1682 conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd'))
1684 conf.set10('ENABLE_SSH_PROXY_CONFIG', sshconfdir != 'no')
1685 conf.set10('ENABLE_SSH_USERDB_CONFIG', conf.get('ENABLE_USERDB') == 1 and sshdconfdir != 'no')
1687 conf.set10('SYSTEMD_SLOW_TESTS_DEFAULT', slow_tests)
1689 #####################################################################
1691 pymod = import('python')
1692 python = pymod.find_installation('python3', required : true, modules : ['jinja2'])
1693 python_39 = python.language_version().version_compare('>=3.9')
1695 #####################################################################
1697 if conf.get('BPF_FRAMEWORK') == 1
1698         bpf_clang_flags = [
1699                 '-std=gnu11',
1700                 '-Wno-compare-distinct-pointer-types',
1701                 '-fno-stack-protector',
1702                 '-O2',
1703                 '-target',
1704                 'bpf',
1705                 '-g',
1706                 '-c',
1707         ]
1709         bpf_gcc_flags = [
1710                 '-std=gnu11',
1711                 '-fno-stack-protector',
1712                 '-fno-ssa-phiopt',
1713                 '-O2',
1714                 '-mcpu=v3',
1715                 '-mco-re',
1716                 '-gbtf',
1717                 '-c',
1718         ]
1720         # Generate defines that are appropriate to tell the compiler what architecture
1721         # we're compiling for. By default we just map meson's cpu_family to __<cpu_family>__.
1722         # This dictionary contains the exceptions where this doesn't work.
1723         #
1724         # C.f. https://mesonbuild.com/Reference-tables.html#cpu-families
1725         # and src/basic/missing_syscall_def.h.
1726         cpu_arch_defines = {
1727                 'ppc'     : ['-D__powerpc__'],
1728                 'ppc64'   : ['-D__powerpc64__', '-D_CALL_ELF=2'],
1729                 'riscv32' : ['-D__riscv', '-D__riscv_xlen=32'],
1730                 'riscv64' : ['-D__riscv', '-D__riscv_xlen=64'],
1731                 'x86'     : ['-D__i386__'],
1733                 # For arm, assume hardware fp is available.
1734                 'arm'     : ['-D__arm__', '-D__ARM_PCS_VFP'],
1735         }
1737         bpf_arch_flags = cpu_arch_defines.get(host_machine.cpu_family(),
1738                                               ['-D__@0@__'.format(host_machine.cpu_family())])
1739         if bpf_compiler == 'gcc'
1740                 bpf_arch_flags += ['-m' + host_machine.endian() + '-endian']
1741         endif
1743         libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir')
1745         bpf_o_unstripped_cmd = []
1746         if bpf_compiler == 'clang'
1747                 bpf_o_unstripped_cmd += [
1748                         clang,
1749                         bpf_clang_flags,
1750                         bpf_arch_flags,
1751                 ]
1752         elif bpf_compiler == 'gcc'
1753                 bpf_o_unstripped_cmd += [
1754                         bpf_gcc,
1755                         bpf_gcc_flags,
1756                         bpf_arch_flags,
1757                 ]
1758         endif
1760         bpf_o_unstripped_cmd += ['-I.']
1762         if not meson.is_cross_build()
1763                 target_triplet_cmd = run_command('gcc', '-dumpmachine', check: false)
1764                 if target_triplet_cmd.returncode() == 0
1765                         target_triplet = target_triplet_cmd.stdout().strip()
1766                         bpf_o_unstripped_cmd += [
1767                                 '-isystem',
1768                                 '/usr/include/@0@'.format(target_triplet)
1769                         ]
1770                 endif
1771         endif
1773         bpf_o_unstripped_cmd += [
1774                 '-idirafter',
1775                 libbpf_include_dir,
1776                 '@INPUT@',
1777                 '-o',
1778                 '@OUTPUT@'
1779         ]
1781         if bpftool_strip
1782                 bpf_o_cmd = [
1783                         bpftool,
1784                         'gen',
1785                         'object',
1786                         '@OUTPUT@',
1787                         '@INPUT@'
1788                 ]
1789         elif bpf_compiler == 'clang'
1790                 bpf_o_cmd = [
1791                         llvm_strip,
1792                         '-g',
1793                         '@INPUT@',
1794                         '-o',
1795                         '@OUTPUT@'
1796                 ]
1797         endif
1799         skel_h_cmd = [
1800                 bpftool,
1801                 'gen',
1802                 'skeleton',
1803                 '@INPUT@'
1804         ]
1805 endif
1807 #####################################################################
1809 efi_arch = {
1810         'aarch64'     : 'aa64',
1811         'arm'         : 'arm',
1812         'loongarch32' : 'loongarch32',
1813         'loongarch64' : 'loongarch64',
1814         'riscv32'     : 'riscv32',
1815         'riscv64'     : 'riscv64',
1816         'x86_64'      : 'x64',
1817         'x86'         : 'ia32',
1818 }.get(host_machine.cpu_family(), '')
1820 pyelftools = pymod.find_installation('python3',
1821                                      required : get_option('bootloader'),
1822                                      modules : ['elftools'])
1824 have = get_option('bootloader').require(
1825         pyelftools.found() and get_option('efi') and efi_arch != '',
1826         error_message : 'unsupported EFI arch or EFI support is disabled').allowed()
1827 conf.set10('ENABLE_BOOTLOADER', have)
1828 conf.set_quoted('EFI_MACHINE_TYPE_NAME', have ? efi_arch : '')
1830 efi_arch_alt = ''
1831 efi_cpu_family_alt = ''
1832 if have and efi_arch == 'x64' and cc.links('''
1833                 #include <limits.h>
1834                 int main(int argc, char *argv[]) {
1835                         return __builtin_popcount(argc - CHAR_MAX);
1836                 }''', args : ['-m32', '-march=i686'], name : '32bit build possible')
1837         efi_arch_alt = 'ia32'
1838         efi_cpu_family_alt = 'x86'
1839 endif
1841 pefile = pymod.find_installation('python3', required: false, modules : ['pefile'])
1843 want_ukify = get_option('ukify').require(python_39 and (want_tests != 'true' or pefile.found()), error_message : 'Python >= 3.9 and pefile required').allowed()
1844 conf.set10('ENABLE_UKIFY', want_ukify)
1846 #####################################################################
1848 check_efi_alignment_py = find_program('tools/check-efi-alignment.py')
1850 #####################################################################
1852 use_provided_vmlinux_h = false
1853 use_generated_vmlinux_h = false
1854 provided_vmlinux_h_path = get_option('vmlinux-h-path')
1856 # For the more complex BPF programs we really want a vmlinux.h (which is arch
1857 # specific, but only somewhat bound to kernel version). Ideally the kernel
1858 # development headers would ship that, but right now they don't. Hence address
1859 # this in two ways:
1861 # 1. Provide a vmlinux.h at build time
1862 # 2. Generate the file on the fly where possible (which requires /sys/ to be mounted)
1864 # We generally prefer the former (to support reproducible builds), but will
1865 # fallback to the latter.
1867 if conf.get('BPF_FRAMEWORK') == 1
1868         enable_vmlinux_h = get_option('vmlinux-h')
1870         if enable_vmlinux_h == 'auto'
1871                 if provided_vmlinux_h_path != ''
1872                         use_provided_vmlinux_h = true
1873                 elif fs.exists('/sys/kernel/btf/vmlinux') and \
1874                                 bpftool.found() and \
1875                                 (host_machine.cpu_family() == build_machine.cpu_family()) and \
1876                                 host_machine.cpu_family() in ['x86_64', 'aarch64']
1878                         # We will only generate a vmlinux.h from the running
1879                         # kernel if the host and build machine are of the same
1880                         # family. Also for now we focus on x86_64 and aarch64,
1881                         # since other archs don't seem to be ready yet.
1883                         use_generated_vmlinux_h = true
1884                 endif
1885         elif enable_vmlinux_h == 'provided'
1886                 use_provided_vmlinux_h = true
1887         elif enable_vmlinux_h == 'generated'
1888                 if not fs.exists('/sys/kernel/btf/vmlinux')
1889                         error('BTF data from kernel not available (/sys/kernel/btf/vmlinux missing), cannot generate vmlinux.h, but was asked to.')
1890                 endif
1891                 if not bpftool.found()
1892                         error('bpftool not available, cannot generate vmlinux.h, but was asked to.')
1893                 endif
1894                 use_generated_vmlinux_h = true
1895         endif
1896 endif
1898 if use_provided_vmlinux_h
1899         if not fs.exists(provided_vmlinux_h_path)
1900                 error('Path to provided vmlinux.h does not exist.')
1901         endif
1902         vmlinux_h_dependency = []
1903         bpf_o_unstripped_cmd += ['-I' + fs.parent(provided_vmlinux_h_path)]
1904         message('Using provided @0@'.format(provided_vmlinux_h_path))
1905 elif use_generated_vmlinux_h
1906         vmlinux_h_dependency = custom_target(
1907                 'vmlinux.h',
1908                 output: 'vmlinux.h',
1909                 command : [ bpftool, 'btf', 'dump', 'file', '/sys/kernel/btf/vmlinux', 'format', 'c' ],
1910                 capture : true)
1912         bpf_o_unstripped_cmd += ['-I' + fs.parent(vmlinux_h_dependency.full_path())]
1913         message('Using generated @0@'.format(vmlinux_h_dependency.full_path()))
1914 else
1915         message('Using neither provided nor generated vmlinux.h, some features will not be available.')
1916 endif
1918 conf.set10('HAVE_VMLINUX_H', use_provided_vmlinux_h or use_generated_vmlinux_h)
1920 #####################################################################
1922 check_version_history_py = find_program('tools/check-version-history.py')
1923 elf2efi_py = find_program('tools/elf2efi.py')
1924 export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
1925 generate_gperfs = find_program('tools/generate-gperfs.py')
1926 make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py')
1927 make_directive_index_py = find_program('tools/make-directive-index.py')
1928 sync_docs_py = find_program('tools/sync-docs.py')
1929 make_man_index_py = find_program('tools/make-man-index.py')
1930 meson_render_jinja2 = find_program('tools/meson-render-jinja2.py')
1931 update_dbus_docs_py = find_program('tools/update-dbus-docs.py')
1932 update_hwdb_autosuspend_sh = find_program('tools/update-hwdb-autosuspend.sh')
1933 update_hwdb_sh = find_program('tools/update-hwdb.sh')
1934 update_man_rules_py = find_program('tools/update-man-rules.py')
1935 update_syscall_tables_sh = find_program('tools/update-syscall-tables.sh')
1936 xml_helper_py = find_program('tools/xml_helper.py')
1938 #####################################################################
1940 version_tag = get_option('version-tag')
1941 if version_tag == ''
1942         version_tag = meson.project_version()
1943 endif
1945 conf.set_quoted('VERSION_TAG', version_tag)
1947 vcs_tag = get_option('vcs-tag')
1948 command = ['sh', '-c',
1949            vcs_tag and fs.exists(project_source_root / '.git') ?
1950                    'echo "-g$(git -C . describe --abbrev=7 --match="" --always --dirty=^)"' : ':']
1951 version_h = vcs_tag(
1952         input : 'src/version/version.h.in',
1953         output : 'version.h',
1954         fallback : '',
1955         command : command,
1958 shared_lib_tag = get_option('shared-lib-tag')
1959 if shared_lib_tag == ''
1960         shared_lib_tag = meson.project_version().split('~')[0]
1961 endif
1963 #####################################################################
1965 if get_option('b_coverage')
1966         userspace_c_args += ['-include', 'src/basic/coverage.h']
1967 endif
1969 #####################################################################
1971 config_h = configure_file(
1972         output : 'config.h',
1973         configuration : conf)
1975 userspace_c_args += ['-include', 'config.h']
1977 jinja2_cmdline = [meson_render_jinja2, config_h]
1979 userspace = declare_dependency(
1980         compile_args : userspace_c_args,
1981         link_args : userspace_c_ld_args,
1982         sources : version_h,
1985 man_page_depends = []
1987 #####################################################################
1989 simple_tests = []
1990 libsystemd_tests = []
1991 simple_fuzzers = []
1992 catalogs = []
1993 modules = [] # nss, pam, and other plugins
1994 executables = []
1995 executables_by_name = {}
1996 fuzzer_exes = []
1998 # binaries that have --help and are intended for use by humans,
1999 # usually, but not always, installed in /bin.
2000 public_programs = []
2002 # D-Bus introspection XML export
2003 dbus_programs = []
2005 # A list of boot stubs. Required for testing of ukify.
2006 boot_stubs = []
2008 build_dir_include = include_directories('.')
2010 basic_includes = include_directories(
2011         'src/basic',
2012         'src/fundamental',
2013         'src/systemd',
2014         '.')
2016 libsystemd_includes = [basic_includes, include_directories(
2017         'src/libsystemd/sd-bus',
2018         'src/libsystemd/sd-device',
2019         'src/libsystemd/sd-event',
2020         'src/libsystemd/sd-hwdb',
2021         'src/libsystemd/sd-id128',
2022         'src/libsystemd/sd-journal',
2023         'src/libsystemd/sd-netlink',
2024         'src/libsystemd/sd-network',
2025         'src/libsystemd/sd-resolve')]
2027 includes = [libsystemd_includes, include_directories('src/shared')]
2029 subdir('po')
2030 subdir('catalog')
2031 subdir('src/fundamental')
2032 subdir('src/basic')
2033 subdir('src/libsystemd')
2034 subdir('src/shared')
2035 subdir('src/libudev')
2037 libsystemd = shared_library(
2038         'systemd',
2039         version : libsystemd_version,
2040         include_directories : libsystemd_includes,
2041         link_args : ['-shared',
2042                      '-Wl,--version-script=' + libsystemd_sym_path],
2043         link_with : [libbasic],
2044         link_whole : [libsystemd_static],
2045         dependencies : [librt,
2046                         threads,
2047                         userspace],
2048         link_depends : libsystemd_sym,
2049         install : true,
2050         install_tag: 'libsystemd',
2051         install_dir : libdir)
2053 alias_target('libsystemd', libsystemd)
2055 install_libsystemd_static = static_library(
2056         'systemd',
2057         libsystemd_sources,
2058         basic_sources,
2059         fundamental_sources,
2060         include_directories : libsystemd_includes,
2061         build_by_default : static_libsystemd != 'false',
2062         install : static_libsystemd != 'false',
2063         install_tag: 'libsystemd',
2064         install_dir : libdir,
2065         pic : static_libsystemd_pic,
2066         dependencies : [libblkid,
2067                         libcap,
2068                         libdl,
2069                         libgcrypt_cflags,
2070                         liblz4_cflags,
2071                         libmount,
2072                         libopenssl,
2073                         librt,
2074                         libxz_cflags,
2075                         libzstd_cflags,
2076                         threads,
2077                         userspace],
2078         c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
2080 libudev = shared_library(
2081         'udev',
2082         version : libudev_version,
2083         include_directories : includes,
2084         link_args : ['-shared',
2085                      '-Wl,--version-script=' + libudev_sym_path],
2086         link_with : [libsystemd_static, libshared_static],
2087         link_whole : libudev_basic,
2088         dependencies : [threads,
2089                         userspace],
2090         link_depends : libudev_sym,
2091         install : true,
2092         install_tag: 'libudev',
2093         install_dir : libdir)
2095 alias_target('libudev', libudev)
2097 install_libudev_static = static_library(
2098         'udev',
2099         basic_sources,
2100         fundamental_sources,
2101         shared_sources,
2102         libsystemd_sources,
2103         libudev_sources,
2104         include_directories : includes,
2105         build_by_default : static_libudev != 'false',
2106         install : static_libudev != 'false',
2107         install_tag: 'libudev',
2108         install_dir : libdir,
2109         link_depends : libudev_sym,
2110         dependencies : [libmount,
2111                         libshared_deps,
2112                         userspace],
2113         c_args : static_libudev_pic ? [] : ['-fno-PIC'],
2114         pic : static_libudev_pic)
2116 #####################################################################
2118 runtest_env = custom_target(
2119         'systemd-runtest.env',
2120         output : 'systemd-runtest.env',
2121         command : [sh, '-c',
2122                    '{ echo SYSTEMD_TEST_DATA=@0@; echo SYSTEMD_CATALOG_DIR=@1@; } >@OUTPUT@'.format(
2123                            project_source_root / 'test',
2124                            project_build_root / 'catalog')],
2125         depends : catalogs,
2126         build_by_default : true)
2128 test_cflags = ['-DTEST_CODE=1']
2129 # We intentionally do not do inline initializations with definitions for a
2130 # bunch of _cleanup_ variables in tests, to ensure valgrind is triggered if we
2131 # use the variable unexpectedly. This triggers a lot of maybe-uninitialized
2132 # false positives when the combination of -O2 and -flto is used. Suppress them.
2133 if '-O2' in c_args and '-flto=auto' in c_args
2134         test_cflags += cc.first_supported_argument('-Wno-maybe-uninitialized')
2135 endif
2137 #####################################################################
2139 executable_template = {
2140         'include_directories' : includes,
2141         'link_with' : libshared,
2142         'install_rpath' : pkglibdir,
2143         'install' : true,
2146 generator_template = executable_template + {
2147         'install_dir' : systemgeneratordir,
2150 libexec_template = executable_template + {
2151         'install_dir' : libexecdir,
2154 executable_additional_kwargs = {
2155         'dependencies' : userspace,
2158 test_template = executable_template + {
2159         'build_by_default' : want_tests != 'false',
2160         'install' : install_tests,
2161         'install_dir' : unittestsdir,
2164 test_additional_kwargs = {
2165         'c_args' : test_cflags,
2166         'link_depends' : runtest_env,
2169 fuzz_template = executable_template + {
2170         'build_by_default' : fuzzer_build,
2171         'install' : false,
2174 if want_ossfuzz or (want_libfuzzer and fuzzing_engine.found())
2175         fuzz_additional_kwargs = {
2176                 'dependencies' : fuzzing_engine,
2177         }
2178 elif want_libfuzzer and not fuzzing_engine.found()
2179         fuzz_additional_kwargs = {
2180                 'link_args' : ['-fsanitize=fuzzer'],
2181         }
2182 else
2183         fuzz_additional_kwargs = {
2184                 'sources' : files('src/fuzz/fuzz-main.c'),
2185         }
2186 endif
2187 fuzz_additional_kwargs += {
2188         'include_directories' : include_directories('src/fuzz'),
2189         'c_args' : test_cflags,
2192 nss_template = {
2193         'version' : '2',
2194         'include_directories' : includes,
2195         # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
2196         'link_args' : ['-z', 'nodelete'],
2197         'link_with' : [
2198                 libsystemd_static,
2199                 libshared_static,
2200                 libbasic,
2201         ],
2202         'dependencies' : [
2203                 librt,
2204                 threads,
2205         ],
2206         'install' : true,
2207         'install_tag' : 'nss',
2208         'install_dir' : libdir,
2211 pam_template = {
2212         'name_prefix' : '',
2213         'include_directories' : includes,
2214         'link_with' : [
2215                 libsystemd_static,
2216                 libshared_static,
2217         ],
2218         'dependencies' : [
2219                 libpam_misc,
2220                 libpam,
2221                 threads,
2222         ],
2223         'install' : true,
2224         'install_tag' : 'pam',
2225         'install_dir' : pamlibdir,
2228 module_additional_kwargs = {
2229         'link_args' : ['-shared'],
2230         'dependencies' : userspace,
2233 #####################################################################
2235 # systemd-analyze requires 'libcore'
2236 subdir('src/core')
2237 # systemd-networkd requires 'libsystemd_network'
2238 subdir('src/libsystemd-network')
2239 # hwdb requires 'udev_link_with' and 'udev_rpath'
2240 subdir('src/udev')
2242 subdir('src/ac-power')
2243 subdir('src/analyze')
2244 subdir('src/ask-password')
2245 subdir('src/backlight')
2246 subdir('src/battery-check')
2247 subdir('src/binfmt')
2248 subdir('src/boot')
2249 subdir('src/boot/efi')
2250 subdir('src/busctl')
2251 subdir('src/cgls')
2252 subdir('src/cgroups-agent')
2253 subdir('src/cgtop')
2254 subdir('src/coredump')
2255 subdir('src/creds')
2256 subdir('src/cryptenroll')
2257 subdir('src/cryptsetup')
2258 subdir('src/debug-generator')
2259 subdir('src/delta')
2260 subdir('src/detect-virt')
2261 subdir('src/dissect')
2262 subdir('src/environment-d-generator')
2263 subdir('src/escape')
2264 subdir('src/firstboot')
2265 subdir('src/fsck')
2266 subdir('src/fstab-generator')
2267 subdir('src/getty-generator')
2268 subdir('src/gpt-auto-generator')
2269 subdir('src/hibernate-resume')
2270 subdir('src/home')
2271 subdir('src/hostname')
2272 subdir('src/hwdb')
2273 subdir('src/id128')
2274 subdir('src/import')
2275 subdir('src/initctl')
2276 subdir('src/integritysetup')
2277 subdir('src/journal')
2278 subdir('src/journal-remote')
2279 subdir('src/kernel-install')
2280 subdir('src/locale')
2281 subdir('src/login')
2282 subdir('src/machine')
2283 subdir('src/machine-id-setup')
2284 subdir('src/mountfsd')
2285 subdir('src/modules-load')
2286 subdir('src/mount')
2287 subdir('src/network')
2288 subdir('src/notify')
2289 subdir('src/nspawn')
2290 subdir('src/nsresourced')
2291 subdir('src/nss-myhostname')
2292 subdir('src/nss-mymachines')
2293 subdir('src/nss-resolve')
2294 subdir('src/nss-systemd')
2295 subdir('src/oom')
2296 subdir('src/partition')
2297 subdir('src/path')
2298 subdir('src/pcrextend')
2299 subdir('src/pcrlock')
2300 subdir('src/portable')
2301 subdir('src/pstore')
2302 subdir('src/quotacheck')
2303 subdir('src/random-seed')
2304 subdir('src/rc-local-generator')
2305 subdir('src/remount-fs')
2306 subdir('src/reply-password')
2307 subdir('src/resolve')
2308 subdir('src/rfkill')
2309 subdir('src/rpm')
2310 subdir('src/run')
2311 subdir('src/run-generator')
2312 subdir('src/shutdown')
2313 subdir('src/sleep')
2314 subdir('src/socket-activate')
2315 subdir('src/socket-proxy')
2316 subdir('src/ssh-generator')
2317 subdir('src/stdio-bridge')
2318 subdir('src/sulogin-shell')
2319 subdir('src/sysctl')
2320 subdir('src/sysext')
2321 subdir('src/system-update-generator')
2322 subdir('src/systemctl')
2323 subdir('src/sysupdate')
2324 subdir('src/sysusers')
2325 subdir('src/sysv-generator')
2326 subdir('src/storagetm')
2327 subdir('src/timedate')
2328 subdir('src/timesync')
2329 subdir('src/tmpfiles')
2330 subdir('src/tpm2-setup')
2331 subdir('src/tty-ask-password-agent')
2332 subdir('src/update-done')
2333 subdir('src/update-utmp')
2334 subdir('src/user-sessions')
2335 subdir('src/userdb')
2336 subdir('src/varlinkctl')
2337 subdir('src/vconsole')
2338 subdir('src/veritysetup')
2339 subdir('src/vmspawn')
2340 subdir('src/volatile-root')
2341 subdir('src/vpick')
2342 subdir('src/xdg-autostart-generator')
2344 subdir('src/systemd')
2346 subdir('src/test')
2347 subdir('src/fuzz')
2348 subdir('src/ukify/test')  # needs to be last for test_env variable
2349 subdir('test/fuzz')
2351 subdir('mime')
2353 alias_target('devel', libsystemd_pc, libudev_pc, systemd_pc, udev_pc)
2355 #####################################################################
2357 foreach test : simple_tests
2358         executables += test_template + { 'sources' : [test] }
2359 endforeach
2361 foreach test : libsystemd_tests
2362         executables += test_template + test
2363 endforeach
2365 foreach fuzzer : simple_fuzzers
2366         executables += fuzz_template + { 'sources' : [fuzzer] }
2367 endforeach
2369 foreach dict : executables
2370         name = dict.get('name', '')
2371         if name == ''
2372                 name = fs.stem(dict.get('sources')[0])
2373                 assert(name.split('-')[0] in ['test', 'fuzz'])
2374         endif
2376         is_test = name.startswith('test-')
2377         is_fuzz = name.startswith('fuzz-')
2379         build = true
2380         foreach cond : dict.get('conditions', [])
2381                 if conf.get(cond) != 1
2382                         build = false
2383                         break
2384                 endif
2385         endforeach
2386         if not build
2387                 continue
2388         endif
2390         kwargs = {}
2391         foreach key, val : dict
2392                 if key in ['name', 'dbus', 'public', 'conditions',
2393                            'type', 'suite', 'timeout', 'parallel']
2394                         continue
2395                 endif
2397                 kwargs += { key : val }
2398         endforeach
2400         foreach key, val : executable_additional_kwargs
2401                 kwargs += { key : [ kwargs.get(key, []), val ]}
2402         endforeach
2404         if is_test
2405                 kwargs += { 'install_dir' : kwargs.get('install_dir') / dict.get('type', '') }
2406                 foreach key, val : test_additional_kwargs
2407                         kwargs += { key : [ kwargs.get(key, []), val ] }
2408                 endforeach
2409         endif
2411         if is_fuzz
2412                 foreach key, val : fuzz_additional_kwargs
2413                         kwargs += { key : [ kwargs.get(key, []), val ] }
2414                 endforeach
2415         endif
2417         exe = executable(
2418                 name,
2419                 kwargs : kwargs,
2420         )
2422         executables_by_name += { name : exe }
2424         if dict.get('build_by_default', true)
2425                 if dict.get('dbus', false)
2426                         dbus_programs += exe
2427                 endif
2428                 if dict.get('public', false)
2429                         public_programs += exe
2430                 endif
2431         endif
2433         if is_test
2434                 type = dict.get('type', '')
2435                 suite = dict.get('suite', '')
2436                 if suite == ''
2437                         suite = fs.name(fs.parent(dict.get('sources')[0]))
2438                         if suite.startswith('sd-')
2439                                 suite = 'libsystemd'
2440                         endif
2441                 endif
2443                 if type == 'manual'
2444                         message('@0@/@1@ is a manual test'.format(suite, name))
2445                 elif type == 'unsafe' and want_tests != 'unsafe'
2446                         message('@0@/@1@ is an unsafe test'.format(suite, name))
2447                 elif dict.get('build_by_default')
2448                         test(name, exe,
2449                              env : test_env,
2450                              timeout : dict.get('timeout', 30),
2451                              suite : suite,
2452                              is_parallel : dict.get('parallel', true))
2453                 endif
2454         endif
2456         if is_fuzz
2457                 fuzzer_exes += exe
2459                 if want_tests != 'false'
2460                         # Run the fuzz regression tests without any sanitizers enabled.
2461                         # Additional invocations with sanitizers may get added below.
2462                         fuzz_ins = fuzz_regression_tests.get(name, {})
2463                         foreach directive : fuzz_ins.get('directives', [])
2464                                 tt = '@0@_@1@'.format(name, fs.name(directive.full_path()))
2465                                 if tt.substring(45) != ''
2466                                         error('Directive sample name is too long:', directive.full_path())
2467                                 endif
2469                                 test(tt,
2470                                      exe,
2471                                      suite : 'fuzz',
2472                                      args : directive.full_path(),
2473                                      depends : directive)
2474                         endforeach
2475                         foreach file : fuzz_ins.get('files', [])
2476                                 tt = '@0@_@1@'.format(name, fs.name(file))
2477                                 if tt.substring(45) != ''
2478                                         error('Fuzz sample name is too long:', fs.name(file))
2479                                 endif
2481                                 test(tt,
2482                                      exe,
2483                                      suite : 'fuzz',
2484                                      args : file)
2485                         endforeach
2486                 endif
2487         endif
2488 endforeach
2490 alias_target('fuzzers', fuzzer_exes)
2492 #####################################################################
2494 test_dlopen = executables_by_name.get('test-dlopen')
2496 foreach dict : modules
2497         name = dict.get('name')
2498         is_nss = name.startswith('nss_')
2499         is_pam = name.startswith('pam_')
2501         build = true
2502         foreach cond : dict.get('conditions', [])
2503                 if conf.get(cond) != 1
2504                         build = false
2505                         break
2506                 endif
2507         endforeach
2508         if not build
2509                 continue
2510         endif
2512         kwargs = {}
2513         foreach key, val : dict
2514                 if key in ['name', 'conditions', 'version-script']
2515                         continue
2516                 endif
2517                 kwargs += { key : val }
2518         endforeach
2520         kwargs += {
2521                 'link_args' : [
2522                         kwargs.get('link_args', []),
2523                         '-Wl,--version-script=' + dict.get('version-script'),
2524                 ],
2525                 'link_depends' : [
2526                         kwargs.get('link_depends', []),
2527                         dict.get('version-script'),
2528                 ],
2529         }
2530         foreach key, val : module_additional_kwargs
2531                 kwargs += { key : [ kwargs.get(key, []), val ]}
2532         endforeach
2534         lib = shared_library(
2535                 name,
2536                 kwargs : kwargs,
2537         )
2539         if is_nss
2540                 # We cannot use shared_module because it does not support version suffix.
2541                 # Unfortunately shared_library insists on creating the symlink…
2542                 meson.add_install_script(sh, '-c', 'rm $DESTDIR@0@/lib@1@.so'.format(libdir, name),
2543                                          install_tag : 'nss')
2544         endif
2546         if want_tests != 'false' and (is_nss or is_pam)
2547                 test('dlopen-' + name,
2548                      test_dlopen,
2549                      # path to dlopen must include a slash
2550                      args : lib.full_path(),
2551                      depends : lib,
2552                      suite : is_nss ? 'nss' : 'pam')
2553         endif
2554 endforeach
2556 #####################################################################
2558 ukify = custom_target(
2559         'ukify',
2560         input : 'src/ukify/ukify.py',
2561         output : 'ukify',
2562         command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
2563         install : want_ukify,
2564         install_mode : 'rwxr-xr-x',
2565         install_dir : bindir)
2566 if want_ukify
2567         public_programs += ukify
2569         # symlink for backwards compatibility after rename
2570         meson.add_install_script(sh, '-c',
2571                                  ln_s.format(bindir / 'ukify',
2572                                              libexecdir / 'ukify'))
2573 endif
2575 #####################################################################
2577 mkosi = find_program('mkosi', required : false)
2578 if integration_tests and not mkosi.found()
2579         error('Could not find mkosi which is required to run the integration tests')
2580 endif
2582 mkosi_depends = public_programs
2584 foreach executable : ['systemd-journal-remote', 'systemd-measure']
2585         if executable in executables_by_name
2586                 mkosi_depends += [executables_by_name[executable]]
2587         endif
2588 endforeach
2590 if mkosi.found()
2591         custom_target('mkosi',
2592                 build_always_stale : true,
2593                 build_by_default: false,
2594                 console : true,
2595                 output : '.',
2596                 command : [
2597                         'mkosi',
2598                         '--directory', meson.current_source_dir(),
2599                         '--output-dir', meson.current_build_dir() / 'mkosi.output',
2600                         '--cache-dir', meson.current_build_dir() / 'mkosi.cache',
2601                         '--build-dir', meson.current_build_dir() / 'mkosi.builddir',
2602                         '--force',
2603                         '--debug',
2604                         'build',
2605                 ],
2606                 depends : mkosi_depends,
2607         )
2608 endif
2610 ############################################################
2612 subdir('rules.d')
2613 subdir('test')
2615 #####################################################################
2617 subdir('docs/sysvinit')
2618 subdir('docs/var-log')
2619 subdir('hwdb.d')
2620 subdir('man')
2621 subdir('modprobe.d')
2622 subdir('network')
2623 subdir('presets')
2624 subdir('shell-completion/bash')
2625 subdir('shell-completion/zsh')
2626 subdir('sysctl.d')
2627 subdir('sysusers.d')
2628 subdir('tmpfiles.d')
2629 subdir('units')
2631 install_subdir('factory/etc',
2632                install_dir : factorydir)
2633 subdir('factory/templates')
2635 if install_sysconfdir
2636         install_data('xorg/50-systemd-user.sh',
2637                      install_dir : xinitrcdir)
2638 endif
2639 install_data('LICENSE.GPL2',
2640              'LICENSE.LGPL2.1',
2641              'NEWS',
2642              'README',
2643              'docs/CODING_STYLE.md',
2644              'docs/DISTRO_PORTING.md',
2645              'docs/ENVIRONMENT.md',
2646              'docs/HACKING.md',
2647              'docs/TRANSIENT-SETTINGS.md',
2648              'docs/TRANSLATORS.md',
2649              'docs/UIDS-GIDS.md',
2650              install_dir : docdir)
2652 install_subdir('LICENSES',
2653                install_dir : docdir)
2655 install_emptydir(systemdstatedir)
2657 #####################################################################
2659 # Ensure that changes to the docs/ directory do not break the
2660 # basic Github pages build. But only run it in developer mode,
2661 # as it might be fragile due to changes in the tooling, and it is
2662 # not generally useful for users.
2663 jekyll = find_program('jekyll', required : false)
2664 if get_option('mode') == 'developer' and want_tests != 'false' and jekyll.found()
2665         test('github-pages',
2666              jekyll,
2667              suite : 'dist',
2668              args : ['build',
2669                      '--source', project_source_root / 'docs',
2670                      '--destination', project_build_root / '_site'])
2671 endif
2673 #####################################################################
2675 check_help = find_program('tools/check-help.sh')
2676 check_version = find_program('tools/check-version.sh')
2678 foreach exec : public_programs
2679         name = fs.name(exec.full_path())
2680         if want_tests != 'false'
2681                 test('check-help-' + name,
2682                      check_help,
2683                      suite : 'dist',
2684                      args : exec.full_path(),
2685                      depends: exec)
2687                 version = meson.project_version()
2688                 if name == 'udevadm'
2689                         # For compatibility reasons we can't use the full version in udevadm.
2690                         version = version.split('~')[0]
2691                 endif
2693                 test('check-version-' + name,
2694                      check_version,
2695                      suite : 'dist',
2696                      args : [exec.full_path(),
2697                              version],
2698                      depends: exec)
2699         endif
2700 endforeach
2702 # Enable tests for all supported sanitizers
2703 foreach tuple : fuzz_sanitizers
2704         sanitizer = tuple[0]
2705         build = tuple[1]
2707         if cc.has_link_argument('-fsanitize=@0@'.format(sanitizer))
2708                 foreach fuzzer, fuzz_ins : fuzz_regression_tests
2709                         name = '@0@:@1@'.format(fuzzer, sanitizer)
2710                         if want_tests == 'false'
2711                                 message('Not compiling @0@ because tests is set to false'.format(name))
2712                                 continue
2713                         endif
2714                         if not fuzz_tests
2715                                 message('Not compiling @0@ because fuzz-tests is set to false'.format(name))
2716                                 continue
2717                         endif
2718                         exe = custom_target(
2719                                 name,
2720                                 output : name,
2721                                 depends : build,
2722                                 command : [ln, '-fs',
2723                                            build.full_path() / fuzzer,
2724                                            '@OUTPUT@'],
2725                                 build_by_default : true)
2727                         foreach directive : fuzz_ins.get('directives', [])
2728                                 test('@0@_@1@_@2@'.format(fuzzer, fs.name(directive.full_path()), sanitizer),
2729                                      env,
2730                                      suite : 'fuzz+san',
2731                                      env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2732                                      timeout : 60,
2733                                      args : [exe.full_path(), directive.full_path()],
2734                                      depends : directive)
2735                         endforeach
2736                         foreach file : fuzz_ins.get('files', [])
2737                                 test('@0@_@1@_@2@'.format(fuzzer, fs.name(file), sanitizer),
2738                                      env,
2739                                      suite : 'fuzz+san',
2740                                      env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2741                                      timeout : 60,
2742                                      args : [exe.full_path(), file])
2743                         endforeach
2744                 endforeach
2745         endif
2746 endforeach
2748 #####################################################################
2750 if git.found()
2751         all_files = run_command(
2752                 env, '-u', 'GIT_WORK_TREE',
2753                 git, '--git-dir=@0@/.git'.format(project_source_root),
2754                      'ls-files', ':/*.[ch]', ':/*.cc',
2755                 check : false)
2756         if all_files.returncode() == 0
2757                 all_files = files(all_files.stdout().split())
2759                 custom_target(
2760                         'tags',
2761                         output : 'tags',
2762                         command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)
2763                 run_target(
2764                         'ctags',
2765                         command : [env, 'ctags', '--tag-relative=never', '-o', '@0@/tags'.format(project_source_root)] + all_files)
2767                 ############################################
2769                 if want_tests != 'false' and conf.get('BUILD_MODE_DEVELOPER') == 1
2770                         test('check-includes',
2771                              files('tools/check-includes.py'),
2772                              args: all_files,
2773                              env : ['PROJECT_SOURCE_ROOT=@0@'.format(project_source_root)],
2774                              suite : 'headers')
2775                 endif
2776         endif
2778         ####################################################
2780         git_contrib_sh = find_program('tools/git-contrib.sh')
2781         run_target(
2782                 'git-contrib',
2783                 command : [git_contrib_sh])
2785         ####################################################
2787         git_head = run_command(
2788                 git, '--git-dir=@0@/.git'.format(project_source_root),
2789                      'rev-parse', 'HEAD',
2790                 check : false).stdout().strip()
2791         git_head_short = run_command(
2792                 git, '--git-dir=@0@/.git'.format(project_source_root),
2793                      'rev-parse', '--short=7', 'HEAD',
2794                 check : false).stdout().strip()
2796         run_target(
2797                 'git-snapshot',
2798                 command : [git, 'archive',
2799                            '-o', '@0@/systemd-@1@.tar.gz'.format(project_source_root,
2800                                                                  git_head_short),
2801                            '--prefix', 'systemd-@0@/'.format(git_head),
2802                            'HEAD'])
2803 endif
2805 #####################################################################
2807 check_api_docs_sh = find_program('tools/check-api-docs.sh')
2808 run_target(
2809         'check-api-docs',
2810         depends : [man, libsystemd, libudev],
2811         command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
2813 alias_target('update-dbus-docs', update_dbus_docs)
2814 alias_target('update-man-rules', update_man_rules)
2816 if not meson.is_cross_build()
2817         custom_target(
2818                 'export-dbus-interfaces',
2819                 output : fs.name(dbus_interfaces_dir),
2820                 install : dbus_interfaces_dir != 'no',
2821                 install_dir : fs.parent(dbus_interfaces_dir),
2822                 command : [export_dbus_interfaces_py, '@OUTPUT@', dbus_programs])
2823 endif
2825 meson_extract_unit_files = find_program('tools/meson-extract-unit-files.py')
2826 custom_target('installed-unit-files.txt',
2827               output : 'installed-unit-files.txt',
2828               capture : true,
2829               install : want_tests != 'no' and install_tests,
2830               install_dir : testdata_dir,
2831               command : [meson_extract_unit_files, project_build_root])
2833 #####################################################################
2835 alt_time_epoch = run_command('date', '-Is', '-u', '-d', '@@0@'.format(time_epoch),
2836                              check : true).stdout().strip()
2838 summary({
2839         'split bin-sbin' :                  split_bin,
2840         'prefix directory' :                prefixdir,
2841         'sysconf directory' :               sysconfdir,
2842         'include directory' :               includedir,
2843         'lib directory' :                   libdir,
2844         'SysV init scripts' :               sysvinit_path,
2845         'SysV rc?.d directories' :          sysvrcnd_path,
2846         'PAM modules directory' :           pamlibdir,
2847         'PAM configuration directory' :     pamconfdir,
2848         'ssh server configuration directory' : sshdconfdir,
2849         'ssh server privilege separation directory' : sshdprivsepdir,
2850         'ssh client configuration directory' : sshconfdir,
2851         'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
2852         'RPM macros directory' :            rpmmacrosdir,
2853         'modprobe.d directory' :            modprobedir,
2854         'D-Bus policy directory' :          dbuspolicydir,
2855         'D-Bus session directory' :         dbussessionservicedir,
2856         'D-Bus system directory' :          dbussystemservicedir,
2857         'D-Bus interfaces directory' :      dbus_interfaces_dir,
2858         'bash completions directory' :      bashcompletiondir,
2859         'zsh completions directory' :       zshcompletiondir,
2860         'private shared lib version tag' :  shared_lib_tag,
2861         'extra start script' :              get_option('rc-local'),
2862         'debug shell' :                     '@0@ @ @1@'.format(get_option('debug-shell'),
2863                                                                get_option('debug-tty')),
2864         'system UIDs' :                     '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
2865                                                                          conf.get('SYSTEM_ALLOC_UID_MIN')),
2866         'system GIDs' :                     '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
2867                                                                          conf.get('SYSTEM_ALLOC_GID_MIN')),
2868         'dynamic UIDs' :                    '@0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
2869         'container UID bases' :             '@0@…@1@'.format(container_uid_base_min, container_uid_base_max),
2870         'static UID/GID allocations' :      ' '.join(static_ugids),
2871         '/dev/kvm access mode' :            get_option('dev-kvm-mode'),
2872         'render group access mode' :        get_option('group-render-mode'),
2873         'certificate root directory' :      get_option('certificate-root'),
2874         'support URL' :                     support_url,
2875         'nobody user name' :                nobody_user,
2876         'nobody group name' :               nobody_group,
2877         'fallback hostname' :               get_option('fallback-hostname'),
2878         'default compression method' :      compression,
2879         'default DNSSEC mode' :             default_dnssec,
2880         'default DNS-over-TLS mode' :       default_dns_over_tls,
2881         'default mDNS mode' :               default_mdns,
2882         'default LLMNR mode' :              default_llmnr,
2883         'default DNS servers' :             dns_servers.split(' '),
2884         'default NTP servers' :             ntp_servers.split(' '),
2885         'default net.naming_scheme= value': default_net_naming_scheme,
2886         'default KillUserProcesses= value': kill_user_processes,
2887         'default locale' :                  default_locale,
2888         'default nspawn locale' :           nspawn_locale,
2889         'default status unit format' :      status_unit_format_default,
2890         'default user $PATH' :
2891                 default_user_path != '' ? default_user_path : '(same as system services)',
2892         'systemd service watchdog' :        service_watchdog == '' ? 'disabled' : service_watchdog,
2893         'time epoch' :                      '@0@ (@1@)'.format(time_epoch, alt_time_epoch)})
2895 # TODO:
2896 # CFLAGS:   ${OUR_CFLAGS} ${CFLAGS}
2897 # CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
2898 # LDFLAGS:  ${OUR_LDFLAGS} ${LDFLAGS}
2900 found = []
2901 missing = []
2903 foreach tuple : [
2904         # dependencies
2905         ['ACL'],
2906         ['AUDIT'],
2907         ['AppArmor'],
2908         ['IMA'],
2909         ['PAM'],
2910         ['SECCOMP'],
2911         ['SELinux'],
2912         ['SMACK'],
2913         ['blkid'],
2914         ['elfutils'],
2915         ['gcrypt'],
2916         ['gnutls'],
2917         ['libbpf'],
2918         ['libcryptsetup'],
2919         ['libcryptsetup-plugins'],
2920         ['libcurl'],
2921         ['libfdisk'],
2922         ['libfido2'],
2923         ['libidn'],
2924         ['libidn2'],
2925         ['libiptc'],
2926         ['microhttpd'],
2927         ['openssl'],
2928         ['p11kit'],
2929         ['passwdqc'],
2930         ['pcre2'],
2931         ['pwquality'],
2932         ['qrencode'],
2933         ['tpm2'],
2934         ['xkbcommon'],
2936         # compression libs
2937         ['zstd'],
2938         ['lz4'],
2939         ['xz'],
2940         ['zlib'],
2941         ['bzip2'],
2943         # components
2944         ['backlight'],
2945         ['binfmt'],
2946         ['bootloader'],
2947         ['bpf-framework',          conf.get('BPF_FRAMEWORK') == 1],
2948         ['coredump'],
2949         ['efi'],
2950         ['environment.d'],
2951         ['firstboot'],
2952         ['hibernate'],
2953         ['homed'],
2954         ['hostnamed'],
2955         ['hwdb'],
2956         ['importd'],
2957         ['initrd'],
2958         ['kernel-install'],
2959         ['localed'],
2960         ['logind'],
2961         ['machined'],
2962         ['networkd'],
2963         ['nss-myhostname'],
2964         ['nss-mymachines'],
2965         ['nss-resolve'],
2966         ['nss-systemd'],
2967         ['oomd'],
2968         ['portabled'],
2969         ['pstore'],
2970         ['quotacheck'],
2971         ['randomseed'],
2972         ['repart'],
2973         ['resolve'],
2974         ['rfkill'],
2975         ['sysext'],
2976         ['systemd-analyze',        conf.get('ENABLE_ANALYZE') == 1],
2977         ['sysupdate'],
2978         ['sysusers'],
2979         ['storagetm'],
2980         ['timedated'],
2981         ['timesyncd'],
2982         ['tmpfiles'],
2983         ['userdb'],
2984         ['vconsole'],
2985         ['vmspawn'],
2986         ['xdg-autostart'],
2988         # optional features
2989         ['dmi'],
2990         ['idn'],
2991         ['polkit'],
2992         ['nscd'],
2993         ['legacy-pkla',            install_polkit_pkla],
2994         ['kmod'],
2995         ['xenctrl'],
2996         ['dbus'],
2997         ['glib'],
2998         ['tpm'],
2999         ['man pages',              want_man],
3000         ['html pages',             want_html],
3001         ['man page indices',       want_man and have_lxml],
3002         ['SysV compat'],
3003         ['compat-mutable-uid-boundaries'],
3004         ['utmp'],
3005         ['ldconfig'],
3006         ['adm group',              get_option('adm-group')],
3007         ['wheel group',            get_option('wheel-group')],
3008         ['gshadow'],
3009         ['debug hashmap'],
3010         ['debug mmap cache'],
3011         ['debug siphash'],
3012         ['trace logging',          conf.get('LOG_TRACE') == 1],
3013         ['slow tests',             slow_tests],
3014         ['fuzz tests',             fuzz_tests],
3015         ['install tests',          install_tests],
3016         ['link-udev-shared',       get_option('link-udev-shared')],
3017         ['link-systemctl-shared',  get_option('link-systemctl-shared')],
3018         ['link-networkd-shared',   get_option('link-networkd-shared')],
3019         ['link-timesyncd-shared',  get_option('link-timesyncd-shared')],
3020         ['link-journalctl-shared', get_option('link-journalctl-shared')],
3021         ['link-boot-shared',       get_option('link-boot-shared')],
3022         ['link-portabled-shared',  get_option('link-portabled-shared')],
3023         ['first-boot-full-preset'],
3024         ['fexecve'],
3025         ['standalone-binaries',    get_option('standalone-binaries')],
3026         ['coverage',               get_option('b_coverage')],
3029         if tuple.length() >= 2
3030                 cond = tuple[1]
3031         else
3032                 ident1 = 'HAVE_' + tuple[0].underscorify().to_upper()
3033                 ident2 = 'ENABLE_' + tuple[0].underscorify().to_upper()
3034                 cond = conf.get(ident1, 0) == 1 or conf.get(ident2, 0) == 1
3035         endif
3036         if cond
3037                 found += tuple[0]
3038         else
3039                 missing += tuple[0]
3040         endif
3041 endforeach
3043 if static_libsystemd == 'false'
3044         missing += 'static-libsystemd'
3045 else
3046         found += 'static-libsystemd(@0@)'.format(static_libsystemd)
3047 endif
3049 if static_libudev == 'false'
3050         missing += 'static-libudev'
3051 else
3052         found += 'static-libudev(@0@)'.format(static_libudev)
3053 endif
3055 if conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and conf.get('PREFER_OPENSSL') == 1
3056         found += 'cryptolib(openssl)'
3057 elif conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1
3058         found += 'cryptolib(gcrypt)'
3059 else
3060         missing += 'cryptolib'
3061 endif
3063 if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
3064         found += 'DNS-over-TLS(gnutls)'
3065 elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
3066         found += 'DNS-over-TLS(openssl)'
3067 else
3068         missing += 'DNS-over-TLS'
3069 endif
3071 summary({
3072         'enabled' :  ', '.join(found),
3073         'disabled' : ', '.join(missing)},
3074         section : 'Features')