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