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