]> git.ipfire.org Git - thirdparty/systemd.git/blob - meson.build
Merge pull request #31209 from bluca/pidfd_spawn
[thirdparty/systemd.git] / meson.build
1 # SPDX-License-Identifier: LGPL-2.1-or-later
2
3 project('systemd', 'c',
4 version : '255',
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(),
22 description : 'Numerical project version (used where a simple number is expected)')
23
24 # This is to be used instead of meson.source_root(), as the latter will return
25 # the wrong result when systemd is being built as a meson subproject
26 project_source_root = meson.current_source_dir()
27 project_build_root = meson.current_build_dir()
28 relative_source_path = run_command('realpath',
29 '--relative-to=@0@'.format(project_build_root),
30 project_source_root,
31 check : true).stdout().strip()
32 conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path)
33
34 conf.set10('BUILD_MODE_DEVELOPER', get_option('mode') == 'developer',
35 description : 'tailor build to development or release builds')
36
37 feature = get_option('log-message-verification')
38 if feature.auto()
39 have = conf.get('BUILD_MODE_DEVELOPER') == 1
40 else
41 have = feature.enabled()
42 endif
43 conf.set10('LOG_MESSAGE_VERIFICATION', have)
44
45 want_ossfuzz = get_option('oss-fuzz')
46 want_libfuzzer = get_option('llvm-fuzz')
47 if want_ossfuzz and want_libfuzzer
48 error('only one of oss-fuzz or llvm-fuzz can be specified')
49 endif
50
51 fuzzer_build = want_ossfuzz or want_libfuzzer
52
53 # If we're building *not* for actual fuzzing, allow input samples of any size
54 # (for testing and for reproduction of issues discovered with previously-higher
55 # limits).
56 conf.set10('FUZZ_USE_SIZE_LIMIT', fuzzer_build)
57
58 # We'll set this to '1' for EFI builds in a different place.
59 conf.set10('SD_BOOT', false)
60
61 # Create a title-less summary section early, so it ends up first in the output.
62 # More items are added later after they have been detected.
63 summary({'build mode' : get_option('mode')})
64
65 #####################################################################
66
67 # Try to install the git pre-commit hook
68 add_git_hook_sh = find_program('tools/add-git-hook.sh', required : false)
69 if add_git_hook_sh.found()
70 git_hook = run_command(add_git_hook_sh, check : false)
71 if git_hook.returncode() == 0
72 message(git_hook.stdout().strip())
73 endif
74 endif
75
76 #####################################################################
77
78 fs = import('fs')
79 if get_option('split-bin') == 'auto'
80 split_bin = not fs.is_symlink('/usr/sbin')
81 else
82 split_bin = get_option('split-bin') == 'true'
83 endif
84 conf.set10('HAVE_SPLIT_BIN', split_bin,
85 description : 'bin and sbin directories are separate')
86
87 have_standalone_binaries = get_option('standalone-binaries')
88
89 sysvinit_path = get_option('sysvinit-path')
90 sysvrcnd_path = get_option('sysvrcnd-path')
91 conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
92 description : 'SysV init scripts and rcN.d links are supported')
93 conf.set10('CREATE_LOG_DIRS', get_option('create-log-dirs'))
94
95 if get_option('hibernate') and not get_option('initrd')
96 error('hibernate depends on initrd')
97 endif
98
99 conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
100 conf.set10('BUMP_PROC_SYS_FS_NR_OPEN', get_option('bump-proc-sys-fs-nr-open'))
101 conf.set('HIGH_RLIMIT_NOFILE', 512*1024)
102
103 # Meson ignores the preceding arguments when joining paths if an absolute
104 # component is encountered, so this should canonicalize various paths when they
105 # are absolute or relative.
106 prefixdir = get_option('prefix')
107 if not prefixdir.startswith('/')
108 error('Prefix is not absolute: "@0@"'.format(prefixdir))
109 endif
110
111 prefixdir_noslash = '/' + prefixdir.strip('/')
112 bindir = prefixdir / get_option('bindir')
113 sbindir = prefixdir / (split_bin ? 'sbin' : 'bin')
114 sbin_to_bin = split_bin ? '../bin/' : ''
115 libdir = prefixdir / get_option('libdir')
116 sysconfdir = prefixdir / get_option('sysconfdir')
117 includedir = prefixdir / get_option('includedir')
118 datadir = prefixdir / get_option('datadir')
119 localstatedir = '/' / get_option('localstatedir')
120
121 libexecdir = prefixdir / 'lib/systemd'
122 pkglibdir = libdir / 'systemd'
123
124 install_sysconfdir = get_option('install-sysconfdir') != 'false'
125 install_sysconfdir_samples = get_option('install-sysconfdir') == 'true'
126 # Dirs of external packages
127 pkgconfigdatadir = get_option('pkgconfigdatadir') != '' ? get_option('pkgconfigdatadir') : datadir / 'pkgconfig'
128 pkgconfiglibdir = get_option('pkgconfiglibdir') != '' ? get_option('pkgconfiglibdir') : libdir / 'pkgconfig'
129 polkitpolicydir = datadir / 'polkit-1/actions'
130 polkitrulesdir = datadir / 'polkit-1/rules.d'
131 polkitpkladir = localstatedir / 'lib/polkit-1/localauthority/10-vendor.d'
132 xinitrcdir = get_option('xinitrcdir') != '' ? get_option('xinitrcdir') : sysconfdir / 'X11/xinit/xinitrc.d'
133 rpmmacrosdir = get_option('rpmmacrosdir')
134 if rpmmacrosdir != 'no'
135 rpmmacrosdir = prefixdir / rpmmacrosdir
136 endif
137 modprobedir = prefixdir / 'lib/modprobe.d'
138
139 # Our own paths
140 pkgdatadir = datadir / 'systemd'
141 environmentdir = prefixdir / 'lib/environment.d'
142 pkgsysconfdir = sysconfdir / 'systemd'
143 userunitdir = prefixdir / 'lib/systemd/user'
144 userpresetdir = prefixdir / 'lib/systemd/user-preset'
145 tmpfilesdir = prefixdir / 'lib/tmpfiles.d'
146 usertmpfilesdir = prefixdir / 'share/user-tmpfiles.d'
147 sysusersdir = prefixdir / 'lib/sysusers.d'
148 sysctldir = prefixdir / 'lib/sysctl.d'
149 binfmtdir = prefixdir / 'lib/binfmt.d'
150 modulesloaddir = prefixdir / 'lib/modules-load.d'
151 networkdir = prefixdir / 'lib/systemd/network'
152 systemgeneratordir = libexecdir / 'system-generators'
153 usergeneratordir = prefixdir / 'lib/systemd/user-generators'
154 systemenvgeneratordir = prefixdir / 'lib/systemd/system-environment-generators'
155 userenvgeneratordir = prefixdir / 'lib/systemd/user-environment-generators'
156 systemshutdowndir = libexecdir / 'system-shutdown'
157 systemsleepdir = libexecdir / 'system-sleep'
158 systemunitdir = prefixdir / 'lib/systemd/system'
159 systempresetdir = prefixdir / 'lib/systemd/system-preset'
160 udevlibexecdir = prefixdir / 'lib/udev'
161 udevrulesdir = udevlibexecdir / 'rules.d'
162 udevhwdbdir = udevlibexecdir / 'hwdb.d'
163 catalogdir = prefixdir / 'lib/systemd/catalog'
164 kerneldir = prefixdir / 'lib/kernel'
165 kernelinstalldir = kerneldir / 'install.d'
166 factorydir = datadir / 'factory'
167 bootlibdir = prefixdir / 'lib/systemd/boot/efi'
168 testsdir = prefixdir / 'lib/systemd/tests'
169 unittestsdir = testsdir / 'unit-tests'
170 testdata_dir = testsdir / 'testdata'
171 systemdstatedir = localstatedir / 'lib/systemd'
172 catalogstatedir = systemdstatedir / 'catalog'
173 randomseeddir = localstatedir / 'lib/systemd'
174 profiledir = libexecdir / 'portable' / 'profile'
175 repartdefinitionsdir = libexecdir / 'repart/definitions'
176 ntpservicelistdir = prefixdir / 'lib/systemd/ntp-units.d'
177 credstoredir = prefixdir / 'lib/credstore'
178 pcrlockdir = prefixdir / 'lib/pcrlock.d'
179 mimepackagesdir = prefixdir / 'share/mime/packages'
180
181 configfiledir = get_option('configfiledir')
182 if configfiledir == ''
183 configfiledir= sysconfdir
184 endif
185 pkgconfigfiledir = configfiledir / 'systemd'
186
187 docdir = get_option('docdir')
188 if docdir == ''
189 docdir = datadir / 'doc/systemd'
190 endif
191
192 pamlibdir = get_option('pamlibdir')
193 if pamlibdir == ''
194 pamlibdir = libdir / 'security'
195 endif
196
197 pamconfdir = get_option('pamconfdir')
198 if pamconfdir == ''
199 pamconfdir = prefixdir / 'lib/pam.d'
200 endif
201
202 sshconfdir = get_option('sshconfdir')
203 if sshconfdir == ''
204 sshconfdir = sysconfdir / 'ssh/ssh_config.d'
205 endif
206
207 sshdconfdir = get_option('sshdconfdir')
208 if sshdconfdir == ''
209 sshdconfdir = sysconfdir / 'ssh/sshd_config.d'
210 endif
211
212 libcryptsetup_plugins_dir = get_option('libcryptsetup-plugins-dir')
213 if libcryptsetup_plugins_dir == ''
214 libcryptsetup_plugins_dir = libdir / 'cryptsetup'
215 endif
216
217 memory_accounting_default = get_option('memory-accounting-default')
218 status_unit_format_default = get_option('status-unit-format-default')
219 if status_unit_format_default == 'auto'
220 status_unit_format_default = conf.get('BUILD_MODE_DEVELOPER') == 1 ? 'name' : 'description'
221 endif
222
223 conf.set_quoted('BINDIR', bindir)
224 conf.set_quoted('BINFMT_DIR', binfmtdir)
225 conf.set_quoted('BOOTLIBDIR', bootlibdir)
226 conf.set_quoted('CATALOG_DATABASE', catalogstatedir / 'database')
227 conf.set_quoted('CERTIFICATE_ROOT', get_option('certificate-root'))
228 conf.set_quoted('DOC_DIR', docdir)
229 conf.set_quoted('DOCUMENT_ROOT', pkgdatadir / 'gatewayd')
230 conf.set_quoted('ENVIRONMENT_DIR', environmentdir)
231 conf.set_quoted('INCLUDE_DIR', includedir)
232 conf.set_quoted('LIBDIR', libdir)
233 conf.set_quoted('LIBEXECDIR', libexecdir)
234 conf.set_quoted('MODPROBE_DIR', modprobedir)
235 conf.set_quoted('MODULESLOAD_DIR', modulesloaddir)
236 conf.set_quoted('PKGSYSCONFDIR', pkgsysconfdir)
237 conf.set_quoted('POLKIT_AGENT_BINARY_PATH', bindir / 'pkttyagent')
238 conf.set_quoted('PREFIX', prefixdir)
239 conf.set_quoted('PREFIX_NOSLASH', prefixdir_noslash)
240 conf.set_quoted('RANDOM_SEED', randomseeddir / 'random-seed')
241 conf.set_quoted('RANDOM_SEED_DIR', randomseeddir)
242 conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local'))
243 conf.set_quoted('SSHCONFDIR', sshconfdir)
244 conf.set_quoted('SSHDCONFDIR', sshdconfdir)
245 conf.set_quoted('SYSCONF_DIR', sysconfdir)
246 conf.set_quoted('SYSCTL_DIR', sysctldir)
247 conf.set_quoted('SYSTEMCTL_BINARY_PATH', bindir / 'systemctl')
248 conf.set_quoted('SYSTEMD_BINARY_PATH', libexecdir / 'systemd')
249 conf.set_quoted('SYSTEMD_EXECUTOR_BINARY_PATH', libexecdir / 'systemd-executor')
250 conf.set_quoted('SYSTEMD_CATALOG_DIR', catalogdir)
251 conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', libexecdir / 'systemd-cgroups-agent')
252 conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', bindir / 'systemd-cryptsetup')
253 conf.set_quoted('SYSTEMD_EXPORT_PATH', libexecdir / 'systemd-export')
254 conf.set_quoted('SYSTEMD_FSCK_PATH', libexecdir / 'systemd-fsck')
255 conf.set_quoted('SYSTEMD_GROWFS_PATH', libexecdir / 'systemd-growfs')
256 conf.set_quoted('SYSTEMD_HOMEWORK_PATH', libexecdir / 'systemd-homework')
257 conf.set_quoted('SYSTEMD_IMPORT_FS_PATH', libexecdir / 'systemd-import-fs')
258 conf.set_quoted('SYSTEMD_IMPORT_PATH', libexecdir / 'systemd-import')
259 conf.set_quoted('SYSTEMD_INTEGRITYSETUP_PATH', libexecdir / 'systemd-integritysetup')
260 conf.set_quoted('SYSTEMD_KBD_MODEL_MAP', pkgdatadir / 'kbd-model-map')
261 conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP', pkgdatadir / 'language-fallback-map')
262 conf.set_quoted('SYSTEMD_MAKEFS_PATH', libexecdir / 'systemd-makefs')
263 conf.set_quoted('SYSTEMD_PULL_PATH', libexecdir / 'systemd-pull')
264 conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', libexecdir / 'systemd-shutdown')
265 conf.set_quoted('SYSTEMD_TEST_DATA', testdata_dir)
266 conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', bindir / 'systemd-tty-ask-password-agent')
267 conf.set_quoted('SYSTEMD_UPDATE_HELPER_PATH', libexecdir / 'systemd-update-helper')
268 conf.set_quoted('SYSTEMD_USERWORK_PATH', libexecdir / 'systemd-userwork')
269 conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', libexecdir / 'systemd-veritysetup')
270 conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', pkgsysconfdir / 'system')
271 conf.set_quoted('SYSTEM_DATA_UNIT_DIR', systemunitdir)
272 conf.set_quoted('SYSTEM_ENV_GENERATOR_DIR', systemenvgeneratordir)
273 conf.set_quoted('SYSTEM_GENERATOR_DIR', systemgeneratordir)
274 conf.set_quoted('SYSTEM_PRESET_DIR', systempresetdir)
275 conf.set_quoted('SYSTEM_SHUTDOWN_PATH', systemshutdowndir)
276 conf.set_quoted('SYSTEM_SLEEP_PATH', systemsleepdir)
277 conf.set_quoted('SYSTEM_SYSVINIT_PATH', sysvinit_path)
278 conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
279 conf.set_quoted('SYSUSERS_DIR', sysusersdir)
280 conf.set_quoted('TMPFILES_DIR', tmpfilesdir)
281 conf.set_quoted('USER_TMPFILES_DIR', usertmpfilesdir)
282 conf.set_quoted('UDEVLIBEXECDIR', udevlibexecdir)
283 conf.set_quoted('UDEV_HWDB_DIR', udevhwdbdir)
284 conf.set_quoted('UDEV_RULES_DIR', udevrulesdir)
285 conf.set_quoted('USER_CONFIG_UNIT_DIR', pkgsysconfdir / 'user')
286 conf.set_quoted('USER_DATA_UNIT_DIR', userunitdir)
287 conf.set_quoted('USER_ENV_GENERATOR_DIR', userenvgeneratordir)
288 conf.set_quoted('USER_GENERATOR_DIR', usergeneratordir)
289 conf.set_quoted('USER_KEYRING_PATH', pkgsysconfdir / 'import-pubring.gpg')
290 conf.set_quoted('USER_PRESET_DIR', userpresetdir)
291 conf.set_quoted('VENDOR_KEYRING_PATH', libexecdir / 'import-pubring.gpg')
292
293 conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
294 conf.set10('ENABLE_URLIFY', get_option('urlify'))
295 conf.set10('ENABLE_FEXECVE', get_option('fexecve'))
296 conf.set10('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default)
297 conf.set('STATUS_UNIT_FORMAT_DEFAULT', 'STATUS_UNIT_FORMAT_' + status_unit_format_default.to_upper())
298 conf.set_quoted('STATUS_UNIT_FORMAT_DEFAULT_STR', status_unit_format_default)
299
300 conf.set('DEFAULT_TIMEOUT_SEC', get_option('default-timeout-sec'))
301 conf.set('DEFAULT_USER_TIMEOUT_SEC', get_option('default-user-timeout-sec'))
302 conf.set('UPDATE_HELPER_USER_TIMEOUT_SEC', get_option('update-helper-user-timeout-sec'))
303
304 conf.set10('ENABLE_FIRST_BOOT_FULL_PRESET', get_option('first-boot-full-preset'))
305
306 #####################################################################
307
308 cc = meson.get_compiler('c')
309 userspace_c_args = []
310 userspace_c_ld_args = []
311 meson_build_sh = find_program('tools/meson-build.sh')
312
313 want_tests = get_option('tests')
314 slow_tests = want_tests != 'false' and get_option('slow-tests')
315 fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
316 install_tests = get_option('install-tests')
317
318 if add_languages('cpp', native : false, required : fuzzer_build)
319 # Used only for tests
320 cxx = meson.get_compiler('cpp')
321 cxx_cmd = ' '.join(cxx.cmd_array())
322 else
323 cxx_cmd = ''
324 endif
325
326 if want_libfuzzer
327 fuzzing_engine = meson.get_compiler('cpp').find_library('Fuzzer', required : false)
328 if fuzzing_engine.found()
329 userspace_c_args += '-fsanitize-coverage=trace-pc-guard,trace-cmp'
330 elif cc.has_argument('-fsanitize=fuzzer-no-link')
331 userspace_c_args += '-fsanitize=fuzzer-no-link'
332 else
333 error('Looks like neither libFuzzer nor -fsanitize=fuzzer-no-link is supported')
334 endif
335 elif want_ossfuzz
336 fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
337 endif
338
339 # Those generate many false positives, and we do not want to change the code to
340 # avoid them.
341 basic_disabled_warnings = [
342 '-Wno-missing-field-initializers',
343 '-Wno-unused-parameter',
344 '-Wno-nonnull-compare',
345 ]
346
347 possible_common_cc_flags = [
348 '-Warray-bounds', # clang
349 '-Warray-bounds=2',
350 '-Wdate-time',
351 '-Wendif-labels',
352 '-Werror=format=2',
353 '-Werror=format-signedness',
354 '-Werror=implicit-function-declaration',
355 '-Werror=implicit-int',
356 '-Werror=incompatible-pointer-types',
357 '-Werror=int-conversion',
358 '-Werror=missing-declarations',
359 '-Werror=missing-prototypes',
360 '-Werror=overflow',
361 '-Werror=override-init',
362 '-Werror=return-type',
363 '-Werror=shift-count-overflow',
364 '-Werror=shift-overflow=2',
365 '-Werror=strict-flex-arrays',
366 '-Werror=undef',
367 '-Wfloat-equal',
368 # gperf prevents us from enabling this because it does not emit fallthrough
369 # attribute with clang.
370 #'-Wimplicit-fallthrough',
371 '-Wimplicit-fallthrough=5',
372 '-Winit-self',
373 '-Wlogical-op',
374 '-Wmissing-include-dirs',
375 '-Wmissing-noreturn',
376 '-Wnested-externs',
377 '-Wold-style-definition',
378 '-Wpointer-arith',
379 '-Wredundant-decls',
380 '-Wshadow',
381 '-Wstrict-aliasing=2',
382 '-Wstrict-prototypes',
383 '-Wsuggest-attribute=noreturn',
384 '-Wunused-function',
385 '-Wwrite-strings',
386 '-Wzero-length-bounds',
387
388 # negative arguments are correctly detected starting with meson 0.46.
389 '-Wno-error=#warnings', # clang
390 '-Wno-string-plus-int', # clang
391
392 '-fdiagnostics-show-option',
393 '-fno-common',
394 '-fstack-protector',
395 '-fstack-protector-strong',
396 '-fstrict-flex-arrays',
397 '--param=ssp-buffer-size=4',
398 ]
399
400 possible_common_link_flags = [
401 '-fstack-protector',
402 ]
403
404 c_args = get_option('c_args')
405
406 # Our json library does not support -ffinite-math-only, which is enabled by -Ofast or -ffast-math.
407 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)
408 error('-Ofast, -ffast-math, or -ffinite-math-only is specified in c_args.')
409 endif
410
411 # Disable -Wmaybe-uninitialized when compiling with -Os/-O1/-O3/etc. There are
412 # too many false positives with gcc >= 8. Effectively, we only test with -O0
413 # and -O2; this should be enough to catch most important cases without too much
414 # busywork. See https://github.com/systemd/systemd/pull/19226.
415 if cc.get_id() == 'gcc' and (not '02'.contains(get_option('optimization')) or
416 cc.version().version_compare('<10') or
417 '-Os' in c_args or
418 '-O1' in c_args or
419 '-O3' in c_args or
420 '-Og' in c_args)
421 possible_common_cc_flags += '-Wno-maybe-uninitialized'
422 endif
423
424 # Disable -Wno-unused-result with gcc, see
425 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425.
426 if cc.get_id() == 'gcc'
427 possible_common_cc_flags += '-Wno-unused-result'
428 endif
429
430 # --as-needed and --no-undefined are provided by meson by default,
431 # run 'meson configure' to see what is enabled
432 possible_link_flags = [
433 '-Wl,--fatal-warnings',
434 '-Wl,-z,now',
435 '-Wl,-z,relro',
436 ]
437
438 if get_option('b_sanitize') == 'none'
439 possible_link_flags += '-Wl,--warn-common'
440 endif
441
442 if cc.get_id() == 'clang'
443 possible_common_cc_flags += [
444 '-Wno-typedef-redefinition',
445 '-Wno-gnu-variable-sized-type-not-at-end',
446 ]
447 endif
448
449 if get_option('mode') == 'release'
450 # We could enable 'pattern' for developer mode, but that can interfere with
451 # valgrind and sanitizer builds. Also, clang does not zero-initialize unions,
452 # breaking some of our code (https://reviews.llvm.org/D68115).
453 possible_common_cc_flags += '-ftrivial-auto-var-init=zero'
454 endif
455
456 possible_cc_flags = [
457 '-fno-strict-aliasing',
458 '-fstrict-flex-arrays=1',
459 '-fvisibility=hidden',
460 ]
461
462 if get_option('buildtype') != 'debug'
463 possible_cc_flags += [
464 '-ffunction-sections',
465 '-fdata-sections',
466 ]
467
468 possible_link_flags += '-Wl,--gc-sections'
469 endif
470
471 if get_option('mode') == 'developer'
472 possible_cc_flags += '-fno-omit-frame-pointer'
473 endif
474
475 add_project_arguments(
476 cc.get_supported_arguments(
477 basic_disabled_warnings,
478 possible_common_cc_flags
479 ),
480 language : 'c')
481
482 add_project_link_arguments(
483 cc.get_supported_link_arguments(possible_common_link_flags),
484 language : 'c')
485
486 userspace_c_args += cc.get_supported_arguments(possible_cc_flags)
487 userspace_c_ld_args += cc.get_supported_link_arguments(possible_link_flags)
488
489 have = cc.has_argument('-Wzero-length-bounds')
490 conf.set10('HAVE_ZERO_LENGTH_BOUNDS', have)
491
492 if cc.compiles('''
493 #include <time.h>
494 #include <inttypes.h>
495 typedef uint64_t usec_t;
496 usec_t now(clockid_t clock);
497 int main(void) {
498 struct timespec now;
499 return 0;
500 }
501 ''', args: '-Werror=shadow', name : '-Werror=shadow with local shadowing')
502 add_project_arguments('-Werror=shadow', language : 'c')
503 endif
504
505 if cxx_cmd != ''
506 add_project_arguments(cxx.get_supported_arguments(basic_disabled_warnings), language : 'cpp')
507 endif
508
509 cpp = ' '.join(cc.cmd_array() + get_option('c_args')) + ' -E'
510
511 has_wstringop_truncation = cc.has_argument('-Wstringop-truncation')
512
513 #####################################################################
514 # compilation result tests
515
516 conf.set('_GNU_SOURCE', 1)
517 conf.set('__SANE_USERSPACE_TYPES__', true)
518 conf.set10('HAVE_WSTRINGOP_TRUNCATION', has_wstringop_truncation)
519
520 conf.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include <sys/types.h>'))
521 conf.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include <sys/types.h>'))
522 conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
523 conf.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
524 conf.set('SIZEOF_TIMEX_MEMBER', cc.sizeof('typeof(((struct timex *)0)->freq)', prefix : '#include <sys/timex.h>'))
525
526 long_max = cc.compute_int(
527 'LONG_MAX',
528 prefix : '#include <limits.h>',
529 guess : 0x7FFFFFFFFFFFFFFF,
530 high : 0x7FFFFFFFFFFFFFFF)
531 assert(long_max > 100000)
532 conf.set_quoted('LONG_MAX_STR', '@0@'.format(long_max))
533
534 decl_headers = '''
535 #include <dirent.h>
536 #include <uchar.h>
537 #include <sys/mount.h>
538 #include <sys/stat.h>
539 '''
540
541 foreach decl : ['char16_t',
542 'char32_t',
543 'struct mount_attr',
544 'struct statx',
545 'struct dirent64',
546 ]
547
548 # We get -1 if the size cannot be determined
549 have = cc.sizeof(decl, prefix : decl_headers, args : '-D_GNU_SOURCE') > 0
550
551 if decl == 'struct mount_attr'
552 if have
553 want_linux_fs_h = false
554 else
555 have = cc.sizeof(decl,
556 prefix : decl_headers + '#include <linux/fs.h>',
557 args : '-D_GNU_SOURCE') > 0
558 want_linux_fs_h = have
559 endif
560 endif
561
562 if decl == 'struct statx'
563 if have
564 want_linux_stat_h = false
565 else
566 have = cc.sizeof(decl,
567 prefix : decl_headers + '#include <linux/stat.h>',
568 args : '-D_GNU_SOURCE') > 0
569 want_linux_stat_h = have
570 endif
571 endif
572
573 conf.set10('HAVE_' + decl.underscorify().to_upper(), have)
574 endforeach
575
576 conf.set10('WANT_LINUX_STAT_H', want_linux_stat_h)
577 conf.set10('WANT_LINUX_FS_H', want_linux_fs_h)
578
579 foreach ident : ['secure_getenv', '__secure_getenv']
580 conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident))
581 endforeach
582
583 foreach ident : [
584 ['memfd_create', '''#include <sys/mman.h>'''],
585 ['gettid', '''#include <sys/types.h>
586 #include <unistd.h>'''],
587 ['fchmodat2', '''#include <stdlib.h>
588 #include <fcntl.h>'''], # no known header declares fchmodat2
589 ['pivot_root', '''#include <stdlib.h>
590 #include <unistd.h>'''], # no known header declares pivot_root
591 ['ioprio_get', '''#include <sched.h>'''], # no known header declares ioprio_get
592 ['ioprio_set', '''#include <sched.h>'''], # no known header declares ioprio_set
593 ['name_to_handle_at', '''#include <sys/types.h>
594 #include <sys/stat.h>
595 #include <fcntl.h>'''],
596 ['setns', '''#include <sched.h>'''],
597 ['renameat2', '''#include <stdio.h>
598 #include <fcntl.h>'''],
599 ['kcmp', '''#include <linux/kcmp.h>'''],
600 ['keyctl', '''#include <sys/types.h>
601 #include <keyutils.h>'''],
602 ['copy_file_range', '''#include <sys/syscall.h>
603 #include <unistd.h>'''],
604 ['bpf', '''#include <sys/syscall.h>
605 #include <unistd.h>'''],
606 ['statx', '''#include <sys/types.h>
607 #include <sys/stat.h>
608 #include <unistd.h>'''],
609 ['explicit_bzero' , '''#include <string.h>'''],
610 ['reallocarray', '''#include <stdlib.h>'''],
611 ['set_mempolicy', '''#include <stdlib.h>
612 #include <unistd.h>'''],
613 ['get_mempolicy', '''#include <stdlib.h>
614 #include <unistd.h>'''],
615 ['pidfd_send_signal', '''#include <stdlib.h>
616 #include <unistd.h>
617 #include <signal.h>
618 #include <sys/wait.h>'''],
619 ['pidfd_open', '''#include <stdlib.h>
620 #include <unistd.h>
621 #include <signal.h>
622 #include <sys/wait.h>'''],
623 ['rt_sigqueueinfo', '''#include <stdlib.h>
624 #include <unistd.h>
625 #include <signal.h>
626 #include <sys/wait.h>'''],
627 ['rt_tgsigqueueinfo', '''#include <stdlib.h>
628 #include <unistd.h>
629 #include <signal.h>
630 #include <sys/wait.h>'''],
631 ['mallinfo', '''#include <malloc.h>'''],
632 ['mallinfo2', '''#include <malloc.h>'''],
633 ['execveat', '''#include <unistd.h>'''],
634 ['close_range', '''#include <unistd.h>'''],
635 ['epoll_pwait2', '''#include <sys/epoll.h>'''],
636 ['mount_setattr', '''#include <sys/mount.h>'''],
637 ['move_mount', '''#include <sys/mount.h>'''],
638 ['open_tree', '''#include <sys/mount.h>'''],
639 ['fsopen', '''#include <sys/mount.h>'''],
640 ['fsconfig', '''#include <sys/mount.h>'''],
641 ['fsmount', '''#include <sys/mount.h>'''],
642 ['getdents64', '''#include <dirent.h>'''],
643 ['pidfd_spawn', '''#include <spawn.h>'''],
644 ]
645
646 have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
647 conf.set10('HAVE_' + ident[0].to_upper(), have)
648 endforeach
649
650 if cc.has_function('getrandom', prefix : '''#include <sys/random.h>''', args : '-D_GNU_SOURCE')
651 conf.set10('USE_SYS_RANDOM_H', true)
652 conf.set10('HAVE_GETRANDOM', true)
653 else
654 have = cc.has_function('getrandom', prefix : '''#include <linux/random.h>''')
655 conf.set10('USE_SYS_RANDOM_H', false)
656 conf.set10('HAVE_GETRANDOM', have)
657 endif
658
659 #####################################################################
660
661 sh = find_program('sh')
662 echo = find_program('echo')
663 sed = find_program('sed')
664 awk = find_program('awk')
665 stat = find_program('stat')
666 ln = find_program('ln')
667 git = find_program('git', required : false)
668 env = find_program('env')
669 rsync = find_program('rsync', required : false)
670 diff = find_program('diff')
671 find = find_program('find')
672
673 ln_s = ln.full_path() + ' -frsT -- "${DESTDIR:-}@0@" "${DESTDIR:-}@1@"'
674
675 # If -Dxxx-path option is found, use that. Otherwise, check in $PATH,
676 # /usr/sbin, /sbin, and fall back to the default from middle column.
677 progs = [['quotaon', '/usr/sbin/quotaon' ],
678 ['quotacheck', '/usr/sbin/quotacheck' ],
679 ['kmod', '/usr/bin/kmod' ],
680 ['kexec', '/usr/sbin/kexec' ],
681 ['sulogin', '/usr/sbin/sulogin' ],
682 ['mount', '/usr/bin/mount', 'MOUNT_PATH'],
683 ['umount', '/usr/bin/umount', 'UMOUNT_PATH'],
684 ['loadkeys', '/usr/bin/loadkeys', 'KBD_LOADKEYS'],
685 ['setfont', '/usr/bin/setfont', 'KBD_SETFONT'],
686 ['nologin', '/usr/sbin/nologin', ],
687 ]
688 foreach prog : progs
689 path = get_option(prog[0] + '-path')
690 if path != ''
691 message('Using @1@ for @0@'.format(prog[0], path))
692 else
693 exe = find_program(prog[0],
694 '/usr/sbin/' + prog[0],
695 '/sbin/' + prog[0],
696 required: false)
697 path = exe.found() ? exe.full_path() : prog[1]
698 endif
699 name = prog.length() > 2 ? prog[2] : prog[0].to_upper()
700 conf.set_quoted(name, path)
701 endforeach
702
703 conf.set_quoted('TELINIT', get_option('telinit-path'))
704
705 if run_command(ln, '--relative', '--help', check : false).returncode() != 0
706 error('ln does not support --relative (added in coreutils 8.16)')
707 endif
708
709 #####################################################################
710
711 gperf = find_program('gperf')
712
713 gperf_test_format = '''
714 #include <string.h>
715 const char * in_word_set(const char *, @0@);
716 @1@
717 '''
718 gperf_snippet = run_command(sh, '-c', 'echo foo,bar | "$1" -L ANSI-C', '_', gperf,
719 check : true)
720 gperf_test = gperf_test_format.format('size_t', gperf_snippet.stdout())
721 if cc.compiles(gperf_test)
722 gperf_len_type = 'size_t'
723 else
724 gperf_test = gperf_test_format.format('unsigned', gperf_snippet.stdout())
725 if cc.compiles(gperf_test)
726 gperf_len_type = 'unsigned'
727 else
728 error('unable to determine gperf len type')
729 endif
730 endif
731 message('gperf len type is @0@'.format(gperf_len_type))
732 conf.set('GPERF_LEN_TYPE', gperf_len_type,
733 description : 'The type of gperf "len" parameter')
734
735 #####################################################################
736
737 if not cc.has_header('sys/capability.h')
738 error('POSIX caps headers not found')
739 endif
740 foreach header : ['crypt.h',
741 'linux/memfd.h',
742 'linux/vm_sockets.h',
743 'sys/auxv.h',
744 'threads.h',
745 'valgrind/memcheck.h',
746 'valgrind/valgrind.h',
747 'linux/time_types.h',
748 'sys/sdt.h',
749 ]
750
751 conf.set10('HAVE_' + header.underscorify().to_upper(),
752 cc.has_header(header))
753 endforeach
754
755 #####################################################################
756
757 fallback_hostname = get_option('fallback-hostname')
758 if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0] == '-'
759 error('Invalid fallback-hostname configuration')
760 # A more extensive test is done in test-hostname-util. Let's catch
761 # the most obvious errors here so we don't fail with an assert later.
762 endif
763 conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
764
765 default_hierarchy = get_option('default-hierarchy')
766 conf.set_quoted('DEFAULT_HIERARCHY_NAME', default_hierarchy,
767 description : 'default cgroup hierarchy as string')
768 if default_hierarchy == 'legacy'
769 conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_NONE')
770 elif default_hierarchy == 'hybrid'
771 conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_SYSTEMD')
772 else
773 conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_ALL')
774 endif
775
776 extra_net_naming_schemes = []
777 extra_net_naming_map = []
778 foreach scheme: get_option('extra-net-naming-schemes').split(',')
779 if scheme != ''
780 name = scheme.split('=')[0]
781 value = scheme.split('=')[1]
782 NAME = name.underscorify().to_upper()
783 VALUE = []
784 foreach field: value.split('+')
785 VALUE += 'NAMING_' + field.underscorify().to_upper()
786 endforeach
787 extra_net_naming_schemes += 'NAMING_@0@ = @1@,'.format(NAME, '|'.join(VALUE))
788 extra_net_naming_map += '{ "@0@", NAMING_@1@ },'.format(name, NAME)
789 endif
790 endforeach
791 conf.set('EXTRA_NET_NAMING_SCHEMES', ' '.join(extra_net_naming_schemes))
792 conf.set('EXTRA_NET_NAMING_MAP', ' '.join(extra_net_naming_map))
793
794 default_net_naming_scheme = get_option('default-net-naming-scheme')
795 conf.set_quoted('DEFAULT_NET_NAMING_SCHEME', default_net_naming_scheme,
796 description : 'Default naming scheme as a string')
797 if default_net_naming_scheme != 'latest'
798 conf.set('_DEFAULT_NET_NAMING_SCHEME',
799 'NAMING_' + default_net_naming_scheme.underscorify().to_upper(),
800 description : 'Default naming scheme as a constant')
801 endif
802
803 time_epoch = get_option('time-epoch')
804 if time_epoch <= 0
805 time_epoch = run_command(sh, '-c', 'echo "$SOURCE_DATE_EPOCH"', check : true).stdout().strip()
806 if time_epoch == '' and git.found() and fs.is_dir('.git')
807 # If we're in a git repository, use the creation time of the latest git tag.
808 latest_tag = run_command(git, 'describe', '--abbrev=0', '--tags',
809 check : false)
810 if latest_tag.returncode() == 0
811 time_epoch = run_command(
812 git, 'log', '--no-show-signature', '-1', '--format=%at',
813 latest_tag.stdout().strip(),
814 check : false).stdout()
815 endif
816 endif
817 if time_epoch == ''
818 NEWS = files('NEWS')
819 time_epoch = run_command(stat, '-c', '%Y', NEWS,
820 check : true).stdout()
821 endif
822 time_epoch = time_epoch.strip().to_int()
823 endif
824 conf.set('TIME_EPOCH', time_epoch)
825
826 conf.set('CLOCK_VALID_RANGE_USEC_MAX', get_option('clock-valid-range-usec-max'))
827
828 default_user_shell = get_option('default-user-shell')
829 conf.set_quoted('DEFAULT_USER_SHELL', default_user_shell)
830 conf.set_quoted('DEFAULT_USER_SHELL_NAME', fs.name(default_user_shell))
831
832 foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1], # Also see login.defs(5).
833 ['system-uid-max', 'SYS_UID_MAX', 999],
834 ['system-alloc-gid-min', 'SYS_GID_MIN', 1],
835 ['system-gid-max', 'SYS_GID_MAX', 999]]
836 v = get_option(tuple[0])
837 if v <= 0
838 v = run_command(
839 awk,
840 '/^\s*@0@\s+/ { uid=$2 } END { print uid }'.format(tuple[1]),
841 '/etc/login.defs',
842 check : false).stdout().strip()
843 if v == ''
844 v = tuple[2]
845 else
846 v = v.to_int()
847 endif
848 endif
849 conf.set(tuple[0].underscorify().to_upper(), v)
850 endforeach
851 if conf.get('SYSTEM_ALLOC_UID_MIN') >= conf.get('SYSTEM_UID_MAX')
852 error('Invalid uid allocation range')
853 endif
854 if conf.get('SYSTEM_ALLOC_GID_MIN') >= conf.get('SYSTEM_GID_MAX')
855 error('Invalid gid allocation range')
856 endif
857
858 dynamic_uid_min = get_option('dynamic-uid-min')
859 dynamic_uid_max = get_option('dynamic-uid-max')
860 conf.set('DYNAMIC_UID_MIN', dynamic_uid_min)
861 conf.set('DYNAMIC_UID_MAX', dynamic_uid_max)
862
863 container_uid_base_min = get_option('container-uid-base-min')
864 container_uid_base_max = get_option('container-uid-base-max')
865 conf.set('CONTAINER_UID_BASE_MIN', container_uid_base_min)
866 conf.set('CONTAINER_UID_BASE_MAX', container_uid_base_max)
867
868 nobody_user = get_option('nobody-user')
869 nobody_group = get_option('nobody-group')
870
871 if not meson.is_cross_build()
872 getent_result = run_command('getent', 'passwd', '65534', check : false)
873 if getent_result.returncode() == 0
874 name = getent_result.stdout().split(':')[0]
875 if name != nobody_user
876 warning('\n' +
877 '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) +
878 'Your build will result in an user table setup that is incompatible with the local system.')
879 endif
880 endif
881 id_result = run_command('id', '-u', nobody_user, check : false)
882 if id_result.returncode() == 0
883 id = id_result.stdout().strip().to_int()
884 if id != 65534
885 warning('\n' +
886 '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) +
887 'Your build will result in an user table setup that is incompatible with the local system.')
888 endif
889 endif
890
891 getent_result = run_command('getent', 'group', '65534', check : false)
892 if getent_result.returncode() == 0
893 name = getent_result.stdout().split(':')[0]
894 if name != nobody_group
895 warning('\n' +
896 '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) +
897 'Your build will result in an group table setup that is incompatible with the local system.')
898 endif
899 endif
900 id_result = run_command('id', '-g', nobody_group, check : false)
901 if id_result.returncode() == 0
902 id = id_result.stdout().strip().to_int()
903 if id != 65534
904 warning('\n' +
905 '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) +
906 'Your build will result in an group table setup that is incompatible with the local system.')
907 endif
908 endif
909 endif
910 if nobody_user != nobody_group and not (nobody_user == 'nobody' and nobody_group == 'nogroup')
911 warning('\n' +
912 'The configured user name "@0@" and group name "@1@" of the nobody user/group are not equivalent.\n'.format(nobody_user, nobody_group) +
913 'Please re-check that both "nobody-user" and "nobody-group" options are correctly set.')
914 endif
915
916 conf.set_quoted('NOBODY_USER_NAME', nobody_user)
917 conf.set_quoted('NOBODY_GROUP_NAME', nobody_group)
918
919 static_ugids = []
920 foreach option : ['adm-gid',
921 'audio-gid',
922 'cdrom-gid',
923 'dialout-gid',
924 'disk-gid',
925 'input-gid',
926 'kmem-gid',
927 'kvm-gid',
928 'lp-gid',
929 'render-gid',
930 'sgx-gid',
931 'tape-gid',
932 'tty-gid',
933 'users-gid',
934 'utmp-gid',
935 'video-gid',
936 'wheel-gid',
937 'systemd-journal-gid',
938 'systemd-network-uid',
939 'systemd-resolve-uid',
940 'systemd-timesync-uid']
941 name = option.underscorify().to_upper()
942 val = get_option(option)
943
944 # Ensure provided GID argument is numeric, otherwise fall back to default assignment
945 conf.set(name, val > 0 ? val : '-')
946 if val > 0
947 static_ugids += '@0@:@1@'.format(option, val)
948 endif
949 endforeach
950
951 conf.set10('ENABLE_ADM_GROUP', get_option('adm-group'))
952 conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group'))
953
954 dev_kvm_mode = get_option('dev-kvm-mode')
955 conf.set_quoted('DEV_KVM_MODE', dev_kvm_mode) # FIXME: convert to 0o… notation
956 conf.set10('DEV_KVM_UACCESS', dev_kvm_mode != '0666')
957 group_render_mode = get_option('group-render-mode')
958 conf.set_quoted('GROUP_RENDER_MODE', group_render_mode)
959 conf.set10('GROUP_RENDER_UACCESS', group_render_mode != '0666')
960
961 kill_user_processes = get_option('default-kill-user-processes')
962 conf.set10('KILL_USER_PROCESSES', kill_user_processes)
963
964 dns_servers = get_option('dns-servers')
965 conf.set_quoted('DNS_SERVERS', dns_servers)
966
967 ntp_servers = get_option('ntp-servers')
968 conf.set_quoted('NTP_SERVERS', ntp_servers)
969
970 default_locale = get_option('default-locale')
971 conf.set_quoted('SYSTEMD_DEFAULT_LOCALE', default_locale)
972
973 nspawn_locale = get_option('nspawn-locale')
974 conf.set_quoted('SYSTEMD_NSPAWN_LOCALE', nspawn_locale)
975
976 default_keymap = get_option('default-keymap')
977 if default_keymap == ''
978 # We canonicalize empty keymap to '@kernel', as it makes the default value
979 # in the factory provided /etc/vconsole.conf more obvious.
980 default_keymap = '@kernel'
981 endif
982 conf.set_quoted('SYSTEMD_DEFAULT_KEYMAP', default_keymap)
983
984 localegen_path = get_option('localegen-path')
985 if localegen_path != ''
986 conf.set_quoted('LOCALEGEN_PATH', localegen_path)
987 endif
988 conf.set10('HAVE_LOCALEGEN', localegen_path != '')
989
990 conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
991
992 service_watchdog = get_option('service-watchdog')
993 watchdog_value = service_watchdog == '' ? '' : 'WatchdogSec=' + service_watchdog
994 conf.set_quoted('SERVICE_WATCHDOG', watchdog_value)
995
996 conf.set_quoted('SUSHELL', get_option('debug-shell'))
997 conf.set_quoted('DEBUGTTY', get_option('debug-tty'))
998
999 enable_debug_hashmap = false
1000 enable_debug_mmap_cache = false
1001 enable_debug_siphash = false
1002 foreach name : get_option('debug-extra')
1003 if name == 'hashmap'
1004 enable_debug_hashmap = true
1005 elif name == 'mmap-cache'
1006 enable_debug_mmap_cache = true
1007 elif name == 'siphash'
1008 enable_debug_siphash = true
1009 else
1010 message('unknown debug option "@0@", ignoring'.format(name))
1011 endif
1012 endforeach
1013 conf.set10('ENABLE_DEBUG_HASHMAP', enable_debug_hashmap)
1014 conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache)
1015 conf.set10('ENABLE_DEBUG_SIPHASH', enable_debug_siphash)
1016 conf.set10('LOG_TRACE', get_option('log-trace'))
1017
1018 default_user_path = get_option('user-path')
1019 if default_user_path != ''
1020 conf.set_quoted('DEFAULT_USER_PATH', default_user_path)
1021 endif
1022
1023 #####################################################################
1024
1025 threads = dependency('threads')
1026 librt = cc.find_library('rt')
1027 libm = cc.find_library('m')
1028 libdl = cc.find_library('dl')
1029 libcrypt = dependency('libcrypt', 'libxcrypt', required : false)
1030 if not libcrypt.found()
1031 # fallback to use find_library() if libcrypt is provided by glibc, e.g. for LibreELEC.
1032 libcrypt = cc.find_library('crypt')
1033 endif
1034 libcap = dependency('libcap')
1035
1036 # On some architectures, libatomic is required. But on some installations,
1037 # it is found, but actual linking fails. So let's try to use it opportunistically.
1038 # If it is installed, but not needed, it will be dropped because of --as-needed.
1039 if cc.links('''int main(int argc, char **argv) { return 0; }''',
1040 args : '-latomic',
1041 name : 'libatomic')
1042 libatomic = declare_dependency(link_args : '-latomic')
1043 else
1044 libatomic = []
1045 endif
1046
1047 crypt_header = conf.get('HAVE_CRYPT_H') == 1 ? '''#include <crypt.h>''' : '''#include <unistd.h>'''
1048 foreach ident : [
1049 ['crypt_ra', crypt_header],
1050 ['crypt_preferred_method', crypt_header],
1051 ['crypt_gensalt_ra', crypt_header]]
1052
1053 have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE',
1054 dependencies : libcrypt)
1055 conf.set10('HAVE_' + ident[0].to_upper(), have)
1056 endforeach
1057
1058 bpf_framework = get_option('bpf-framework')
1059 bpf_compiler = get_option('bpf-compiler')
1060 libbpf = dependency('libbpf',
1061 required : bpf_framework,
1062 version : bpf_compiler == 'gcc' ? '>= 1.0.0' : '>= 0.1.0')
1063 conf.set10('HAVE_LIBBPF', libbpf.found())
1064
1065 if not libbpf.found()
1066 conf.set10('BPF_FRAMEWORK', false)
1067 else
1068 clang_found = false
1069 clang_supports_bpf = false
1070 bpf_gcc_found = false
1071 bpftool_strip = false
1072 deps_found = false
1073
1074 if bpf_compiler == 'clang'
1075 # Support 'versioned' clang/llvm-strip binaries, as seen on Debian/Ubuntu
1076 # (like clang-10/llvm-strip-10)
1077 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')
1078 r = find_program('clang',
1079 required : bpf_framework,
1080 version : '>= 10.0.0')
1081 clang_found = r.found()
1082 if clang_found
1083 clang = r.full_path()
1084 endif
1085 else
1086 clang_found = true
1087 clang = cc.cmd_array()
1088 endif
1089
1090 if clang_found
1091 # Check if 'clang -target bpf' is supported.
1092 clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus', check : false).returncode() == 0
1093 endif
1094 elif bpf_compiler == 'gcc'
1095 bpf_gcc = find_program('bpf-gcc',
1096 'bpf-none-gcc',
1097 required : true,
1098 version : '>= 13.1.0')
1099 bpf_gcc_found = bpf_gcc.found()
1100 endif
1101
1102 if clang_supports_bpf or bpf_gcc_found
1103 # Debian installs this in /usr/sbin/ which is not in $PATH.
1104 # We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian.
1105 # We use 'bpftool gen object' subcommand for bpftool strip, it was added by d80b2fcbe0a023619e0fc73112f2a02c2662f6ab (v5.13).
1106 bpftool = find_program('bpftool',
1107 '/usr/sbin/bpftool',
1108 required : bpf_framework.enabled() and bpf_compiler == 'gcc',
1109 version : bpf_compiler == 'gcc' ? '>= 7.0.0' : '>= 5.13.0')
1110
1111 if bpftool.found()
1112 bpftool_strip = true
1113 deps_found = true
1114 elif bpf_compiler == 'clang'
1115 # We require the 'bpftool gen skeleton' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6).
1116 bpftool = find_program('bpftool',
1117 '/usr/sbin/bpftool',
1118 required : bpf_framework,
1119 version : '>= 5.6.0')
1120 endif
1121
1122 # We use `llvm-strip` as a fallback if `bpftool gen object` strip support is not available.
1123 if not bpftool_strip and bpftool.found() and clang_supports_bpf
1124 if not meson.is_cross_build()
1125 llvm_strip_bin = run_command(clang, '--print-prog-name', 'llvm-strip',
1126 check : true).stdout().strip()
1127 else
1128 llvm_strip_bin = 'llvm-strip'
1129 endif
1130 llvm_strip = find_program(llvm_strip_bin,
1131 required : bpf_framework,
1132 version : '>= 10.0.0')
1133 deps_found = llvm_strip.found()
1134 endif
1135 endif
1136
1137 # Can build BPF program from source code in restricted C
1138 conf.set10('BPF_FRAMEWORK', deps_found)
1139 endif
1140
1141 libmount = dependency('mount',
1142 version : fuzzer_build ? '>= 0' : '>= 2.30')
1143
1144 libfdisk = dependency('fdisk',
1145 version : '>= 2.32',
1146 disabler : true,
1147 required : get_option('fdisk'))
1148 conf.set10('HAVE_LIBFDISK', libfdisk.found())
1149
1150 # This prefers pwquality if both are enabled or auto.
1151 feature = get_option('pwquality').disable_auto_if(get_option('passwdqc').enabled())
1152 libpwquality = dependency('pwquality',
1153 version : '>= 1.4.1',
1154 required : feature)
1155 have = libpwquality.found()
1156 if not have
1157 # libpwquality is used for both features for simplicity
1158 libpwquality = dependency('passwdqc',
1159 required : get_option('passwdqc'))
1160 endif
1161 conf.set10('HAVE_PWQUALITY', have)
1162 conf.set10('HAVE_PASSWDQC', not have and libpwquality.found())
1163
1164 libseccomp = dependency('libseccomp',
1165 version : '>= 2.3.1',
1166 required : get_option('seccomp'))
1167 conf.set10('HAVE_SECCOMP', libseccomp.found())
1168
1169 libselinux = dependency('libselinux',
1170 version : '>= 2.1.9',
1171 required : get_option('selinux'))
1172 conf.set10('HAVE_SELINUX', libselinux.found())
1173
1174 libapparmor = dependency('libapparmor',
1175 version : '>= 2.13',
1176 required : get_option('apparmor'))
1177 conf.set10('HAVE_APPARMOR', libapparmor.found())
1178
1179 have = get_option('smack') and get_option('smack-run-label') != ''
1180 conf.set10('HAVE_SMACK_RUN_LABEL', have)
1181 if have
1182 conf.set_quoted('SMACK_RUN_LABEL', get_option('smack-run-label'))
1183 endif
1184
1185 have = get_option('smack') and get_option('smack-default-process-label') != ''
1186 if have
1187 conf.set_quoted('SMACK_DEFAULT_PROCESS_LABEL', get_option('smack-default-process-label'))
1188 endif
1189
1190 feature = get_option('polkit')
1191 libpolkit = dependency('polkit-gobject-1',
1192 required : feature.disabled() ? feature : false)
1193 install_polkit = feature.allowed()
1194 install_polkit_pkla = libpolkit.found() and libpolkit.version().version_compare('< 0.106')
1195 if install_polkit_pkla
1196 message('Old polkit detected, will install pkla files')
1197 endif
1198 conf.set10('ENABLE_POLKIT', install_polkit)
1199
1200 libacl = dependency('libacl',
1201 required : get_option('acl'))
1202 conf.set10('HAVE_ACL', libacl.found())
1203
1204 libaudit = dependency('audit',
1205 required : get_option('audit'))
1206 conf.set10('HAVE_AUDIT', libaudit.found())
1207
1208 libblkid = dependency('blkid',
1209 required : get_option('blkid'))
1210 conf.set10('HAVE_BLKID', libblkid.found())
1211 conf.set10('HAVE_BLKID_PROBE_SET_HINT',
1212 libblkid.found() and cc.has_function('blkid_probe_set_hint', dependencies : libblkid))
1213
1214 libkmod = dependency('libkmod',
1215 version : '>= 15',
1216 required : get_option('kmod'))
1217 conf.set10('HAVE_KMOD', libkmod.found())
1218
1219 libxenctrl = dependency('xencontrol',
1220 version : '>= 4.9',
1221 required : get_option('xenctrl'))
1222 conf.set10('HAVE_XENCTRL', libxenctrl.found())
1223 libxenctrl_cflags = libxenctrl.partial_dependency(includes: true, compile_args: true)
1224
1225 feature = get_option('pam')
1226 libpam = dependency('pam',
1227 required : feature.disabled() ? feature : false)
1228 if not libpam.found()
1229 # Debian older than bookworm and Ubuntu older than 22.10 do not provide the .pc file.
1230 libpam = cc.find_library('pam', required : feature)
1231 endif
1232 libpam_misc = dependency('pam_misc',
1233 required : feature.disabled() ? feature : false)
1234 if not libpam_misc.found()
1235 libpam_misc = cc.find_library('pam_misc', required : feature)
1236 endif
1237 conf.set10('HAVE_PAM', libpam.found() and libpam_misc.found())
1238
1239 libmicrohttpd = dependency('libmicrohttpd',
1240 version : '>= 0.9.33',
1241 required : get_option('microhttpd'))
1242 conf.set10('HAVE_MICROHTTPD', libmicrohttpd.found())
1243
1244 libcryptsetup = get_option('libcryptsetup')
1245 libcryptsetup_plugins = get_option('libcryptsetup-plugins')
1246 if libcryptsetup_plugins.enabled()
1247 if libcryptsetup.disabled()
1248 error('libcryptsetup-plugins cannot be requested without libcryptsetup')
1249 endif
1250 libcryptsetup = libcryptsetup_plugins
1251 endif
1252
1253 libcryptsetup = dependency('libcryptsetup',
1254 version : libcryptsetup_plugins.enabled() ? '>= 2.4.0' : '>= 2.0.1',
1255 required : libcryptsetup)
1256
1257 have = libcryptsetup.found()
1258 foreach ident : ['crypt_set_metadata_size',
1259 'crypt_activate_by_signed_key',
1260 'crypt_token_max',
1261 'crypt_reencrypt_init_by_passphrase',
1262 'crypt_reencrypt',
1263 'crypt_set_data_offset']
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 version_h = vcs_tag(
1857 input : 'src/version/version.h.in',
1858 output : 'version.h',
1859 command: [project_source_root / 'tools/meson-vcs-tag.sh',
1860 project_source_root,
1861 meson.project_version(),
1862 version_tag,
1863 ])
1864
1865 shared_lib_tag = get_option('shared-lib-tag')
1866 if shared_lib_tag == ''
1867 shared_lib_tag = meson.project_version()
1868 endif
1869
1870 #####################################################################
1871
1872 if get_option('b_coverage')
1873 userspace_c_args += ['-include', 'src/basic/coverage.h']
1874 endif
1875
1876 #####################################################################
1877
1878 config_h = configure_file(
1879 output : 'config.h',
1880 configuration : conf)
1881
1882 userspace_c_args += ['-include', 'config.h']
1883
1884 jinja2_cmdline = [meson_render_jinja2, config_h, version_h]
1885
1886 userspace = declare_dependency(
1887 compile_args : userspace_c_args,
1888 link_args : userspace_c_ld_args,
1889 sources : version_h,
1890 )
1891
1892 man_page_depends = []
1893
1894 #####################################################################
1895
1896 simple_tests = []
1897 libsystemd_tests = []
1898 simple_fuzzers = []
1899 catalogs = []
1900 modules = [] # nss, pam, and other plugins
1901 executables = []
1902 executables_by_name = {}
1903 fuzzer_exes = []
1904
1905 # binaries that have --help and are intended for use by humans,
1906 # usually, but not always, installed in /bin.
1907 public_programs = []
1908
1909 # D-Bus introspection XML export
1910 dbus_programs = []
1911
1912 # A list of boot stubs. Required for testing of ukify.
1913 boot_stubs = []
1914
1915 build_dir_include = include_directories('.')
1916
1917 basic_includes = include_directories(
1918 'src/basic',
1919 'src/fundamental',
1920 'src/systemd',
1921 '.')
1922
1923 libsystemd_includes = [basic_includes, include_directories(
1924 'src/libsystemd/sd-bus',
1925 'src/libsystemd/sd-device',
1926 'src/libsystemd/sd-event',
1927 'src/libsystemd/sd-hwdb',
1928 'src/libsystemd/sd-id128',
1929 'src/libsystemd/sd-journal',
1930 'src/libsystemd/sd-netlink',
1931 'src/libsystemd/sd-network',
1932 'src/libsystemd/sd-resolve')]
1933
1934 includes = [libsystemd_includes, include_directories('src/shared')]
1935
1936 subdir('po')
1937 subdir('catalog')
1938 subdir('src/fundamental')
1939 subdir('src/basic')
1940 subdir('src/libsystemd')
1941 subdir('src/shared')
1942 subdir('src/libudev')
1943
1944 libsystemd = shared_library(
1945 'systemd',
1946 version : libsystemd_version,
1947 include_directories : libsystemd_includes,
1948 link_args : ['-shared',
1949 '-Wl,--version-script=' + libsystemd_sym_path],
1950 link_with : [libbasic,
1951 libbasic_gcrypt,
1952 libbasic_compress],
1953 link_whole : [libsystemd_static],
1954 dependencies : [librt,
1955 threads,
1956 userspace],
1957 link_depends : libsystemd_sym,
1958 install : true,
1959 install_tag: 'libsystemd',
1960 install_dir : libdir)
1961
1962 alias_target('libsystemd', libsystemd)
1963
1964 install_libsystemd_static = static_library(
1965 'systemd',
1966 libsystemd_sources,
1967 basic_sources,
1968 basic_gcrypt_sources,
1969 basic_compress_sources,
1970 fundamental_sources,
1971 include_directories : libsystemd_includes,
1972 build_by_default : static_libsystemd != 'false',
1973 install : static_libsystemd != 'false',
1974 install_tag: 'libsystemd',
1975 install_dir : libdir,
1976 pic : static_libsystemd_pic,
1977 dependencies : [libblkid,
1978 libcap,
1979 libdl,
1980 libgcrypt,
1981 liblz4,
1982 libmount,
1983 libopenssl,
1984 librt,
1985 libxz,
1986 libzstd,
1987 threads,
1988 userspace],
1989 c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
1990
1991 libudev = shared_library(
1992 'udev',
1993 version : libudev_version,
1994 include_directories : includes,
1995 link_args : ['-shared',
1996 '-Wl,--version-script=' + libudev_sym_path],
1997 link_with : [libsystemd_static, libshared_static],
1998 link_whole : libudev_basic,
1999 dependencies : [threads,
2000 userspace],
2001 link_depends : libudev_sym,
2002 install : true,
2003 install_tag: 'libudev',
2004 install_dir : libdir)
2005
2006 alias_target('libudev', libudev)
2007
2008 install_libudev_static = static_library(
2009 'udev',
2010 basic_sources,
2011 fundamental_sources,
2012 shared_sources,
2013 libsystemd_sources,
2014 libudev_sources,
2015 include_directories : includes,
2016 build_by_default : static_libudev != 'false',
2017 install : static_libudev != 'false',
2018 install_tag: 'libudev',
2019 install_dir : libdir,
2020 link_depends : libudev_sym,
2021 dependencies : [libmount,
2022 libshared_deps,
2023 userspace],
2024 c_args : static_libudev_pic ? [] : ['-fno-PIC'],
2025 pic : static_libudev_pic)
2026
2027 #####################################################################
2028
2029 runtest_env = custom_target(
2030 'systemd-runtest.env',
2031 output : 'systemd-runtest.env',
2032 command : [sh, '-c',
2033 '{ echo SYSTEMD_TEST_DATA=@0@; echo SYSTEMD_CATALOG_DIR=@1@; } >@OUTPUT@'.format(
2034 project_source_root / 'test',
2035 project_build_root / 'catalog')],
2036 depends : catalogs,
2037 build_by_default : true)
2038
2039 test_cflags = ['-DTEST_CODE=1']
2040 # We intentionally do not do inline initializations with definitions for a
2041 # bunch of _cleanup_ variables in tests, to ensure valgrind is triggered if we
2042 # use the variable unexpectedly. This triggers a lot of maybe-uninitialized
2043 # false positives when the combination of -O2 and -flto is used. Suppress them.
2044 if '-O2' in c_args and '-flto=auto' in c_args
2045 test_cflags += cc.first_supported_argument('-Wno-maybe-uninitialized')
2046 endif
2047
2048 #####################################################################
2049
2050 executable_template = {
2051 'include_directories' : includes,
2052 'link_with' : libshared,
2053 'install_rpath' : pkglibdir,
2054 'install' : true,
2055 }
2056
2057 generator_template = executable_template + {
2058 'install_dir' : systemgeneratordir,
2059 }
2060
2061 libexec_template = executable_template + {
2062 'install_dir' : libexecdir,
2063 }
2064
2065 executable_additional_kwargs = {
2066 'dependencies' : userspace,
2067 }
2068
2069 test_template = executable_template + {
2070 'build_by_default' : want_tests != 'false',
2071 'install' : install_tests,
2072 'install_dir' : unittestsdir,
2073 }
2074
2075 test_additional_kwargs = {
2076 'c_args' : test_cflags,
2077 'link_depends' : runtest_env,
2078 }
2079
2080 fuzz_template = executable_template + {
2081 'build_by_default' : fuzzer_build,
2082 'install' : false,
2083 }
2084
2085 if want_ossfuzz or (want_libfuzzer and fuzzing_engine.found())
2086 fuzz_additional_kwargs = {
2087 'dependencies' : fuzzing_engine,
2088 }
2089 elif want_libfuzzer and not fuzzing_engine.found()
2090 fuzz_additional_kwargs = {
2091 'link_args' : ['-fsanitize=fuzzer'],
2092 }
2093 else
2094 fuzz_additional_kwargs = {
2095 'sources' : files('src/fuzz/fuzz-main.c'),
2096 }
2097 endif
2098 fuzz_additional_kwargs += {
2099 'include_directories' : include_directories('src/fuzz'),
2100 'c_args' : test_cflags,
2101 }
2102
2103 nss_template = {
2104 'version' : '2',
2105 'include_directories' : includes,
2106 # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
2107 'link_args' : ['-z', 'nodelete'],
2108 'link_with' : [
2109 libsystemd_static,
2110 libshared_static,
2111 libbasic,
2112 ],
2113 'dependencies' : [
2114 librt,
2115 threads,
2116 ],
2117 'install' : true,
2118 'install_tag' : 'nss',
2119 'install_dir' : libdir,
2120 }
2121
2122 pam_template = {
2123 'name_prefix' : '',
2124 'include_directories' : includes,
2125 'link_with' : [
2126 libsystemd_static,
2127 libshared_static,
2128 ],
2129 'dependencies' : [
2130 libpam_misc,
2131 libpam,
2132 threads,
2133 ],
2134 'install' : true,
2135 'install_tag' : 'pam',
2136 'install_dir' : pamlibdir,
2137 }
2138
2139 module_additional_kwargs = {
2140 'link_args' : ['-shared'],
2141 'dependencies' : userspace,
2142 }
2143
2144 #####################################################################
2145
2146 # systemd-analyze requires 'libcore'
2147 subdir('src/core')
2148 # systemd-networkd requires 'libsystemd_network'
2149 subdir('src/libsystemd-network')
2150 # hwdb requires 'udev_link_with' and 'udev_rpath'
2151 subdir('src/udev')
2152
2153 subdir('src/ac-power')
2154 subdir('src/analyze')
2155 subdir('src/ask-password')
2156 subdir('src/backlight')
2157 subdir('src/battery-check')
2158 subdir('src/binfmt')
2159 subdir('src/boot')
2160 subdir('src/boot/efi')
2161 subdir('src/busctl')
2162 subdir('src/cgls')
2163 subdir('src/cgroups-agent')
2164 subdir('src/cgtop')
2165 subdir('src/coredump')
2166 subdir('src/creds')
2167 subdir('src/cryptenroll')
2168 subdir('src/cryptsetup')
2169 subdir('src/debug-generator')
2170 subdir('src/delta')
2171 subdir('src/detect-virt')
2172 subdir('src/dissect')
2173 subdir('src/environment-d-generator')
2174 subdir('src/escape')
2175 subdir('src/firstboot')
2176 subdir('src/fsck')
2177 subdir('src/fstab-generator')
2178 subdir('src/getty-generator')
2179 subdir('src/gpt-auto-generator')
2180 subdir('src/hibernate-resume')
2181 subdir('src/home')
2182 subdir('src/hostname')
2183 subdir('src/hwdb')
2184 subdir('src/id128')
2185 subdir('src/import')
2186 subdir('src/initctl')
2187 subdir('src/integritysetup')
2188 subdir('src/journal')
2189 subdir('src/journal-remote')
2190 subdir('src/kernel-install')
2191 subdir('src/locale')
2192 subdir('src/login')
2193 subdir('src/machine')
2194 subdir('src/machine-id-setup')
2195 subdir('src/modules-load')
2196 subdir('src/mount')
2197 subdir('src/network')
2198 subdir('src/notify')
2199 subdir('src/nspawn')
2200 subdir('src/nss-myhostname')
2201 subdir('src/nss-mymachines')
2202 subdir('src/nss-resolve')
2203 subdir('src/nss-systemd')
2204 subdir('src/oom')
2205 subdir('src/partition')
2206 subdir('src/path')
2207 subdir('src/pcrextend')
2208 subdir('src/pcrlock')
2209 subdir('src/portable')
2210 subdir('src/pstore')
2211 subdir('src/quotacheck')
2212 subdir('src/random-seed')
2213 subdir('src/rc-local-generator')
2214 subdir('src/remount-fs')
2215 subdir('src/reply-password')
2216 subdir('src/resolve')
2217 subdir('src/rfkill')
2218 subdir('src/rpm')
2219 subdir('src/run')
2220 subdir('src/run-generator')
2221 subdir('src/shutdown')
2222 subdir('src/sleep')
2223 subdir('src/socket-activate')
2224 subdir('src/socket-proxy')
2225 subdir('src/ssh-generator')
2226 subdir('src/stdio-bridge')
2227 subdir('src/sulogin-shell')
2228 subdir('src/sysctl')
2229 subdir('src/sysext')
2230 subdir('src/system-update-generator')
2231 subdir('src/systemctl')
2232 subdir('src/sysupdate')
2233 subdir('src/sysusers')
2234 subdir('src/sysv-generator')
2235 subdir('src/storagetm')
2236 subdir('src/timedate')
2237 subdir('src/timesync')
2238 subdir('src/tmpfiles')
2239 subdir('src/tpm2-setup')
2240 subdir('src/tty-ask-password-agent')
2241 subdir('src/update-done')
2242 subdir('src/update-utmp')
2243 subdir('src/user-sessions')
2244 subdir('src/userdb')
2245 subdir('src/varlinkctl')
2246 subdir('src/vconsole')
2247 subdir('src/veritysetup')
2248 subdir('src/vmspawn')
2249 subdir('src/volatile-root')
2250 subdir('src/vpick')
2251 subdir('src/xdg-autostart-generator')
2252
2253 subdir('src/systemd')
2254
2255 subdir('src/test')
2256 subdir('src/fuzz')
2257 subdir('src/ukify/test') # needs to be last for test_env variable
2258 subdir('test/fuzz')
2259
2260 subdir('mime')
2261
2262 alias_target('devel', libsystemd_pc, libudev_pc, systemd_pc, udev_pc)
2263
2264 #####################################################################
2265
2266 foreach test : simple_tests
2267 executables += test_template + { 'sources' : [test] }
2268 endforeach
2269
2270 foreach test : libsystemd_tests
2271 executables += test_template + test
2272 endforeach
2273
2274 foreach fuzzer : simple_fuzzers
2275 executables += fuzz_template + { 'sources' : [fuzzer] }
2276 endforeach
2277
2278 foreach dict : executables
2279 name = dict.get('name', '')
2280 if name == ''
2281 name = fs.stem(dict.get('sources')[0])
2282 assert(name.split('-')[0] in ['test', 'fuzz'])
2283 endif
2284
2285 is_test = name.startswith('test-')
2286 is_fuzz = name.startswith('fuzz-')
2287
2288 build = true
2289 foreach cond : dict.get('conditions', [])
2290 if conf.get(cond) != 1
2291 build = false
2292 break
2293 endif
2294 endforeach
2295 if not build
2296 continue
2297 endif
2298
2299 kwargs = {}
2300 foreach key, val : dict
2301 if key in ['name', 'dbus', 'public', 'conditions',
2302 'type', 'suite', 'timeout', 'parallel']
2303 continue
2304 endif
2305
2306 kwargs += { key : val }
2307 endforeach
2308
2309 foreach key, val : executable_additional_kwargs
2310 kwargs += { key : [ kwargs.get(key, []), val ]}
2311 endforeach
2312
2313 if is_test
2314 kwargs += { 'install_dir' : kwargs.get('install_dir') / dict.get('type', '') }
2315 foreach key, val : test_additional_kwargs
2316 kwargs += { key : [ kwargs.get(key, []), val ] }
2317 endforeach
2318 endif
2319
2320 if is_fuzz
2321 foreach key, val : fuzz_additional_kwargs
2322 kwargs += { key : [ kwargs.get(key, []), val ] }
2323 endforeach
2324 endif
2325
2326 exe = executable(
2327 name,
2328 kwargs : kwargs,
2329 )
2330
2331 executables_by_name += { name : exe }
2332
2333 if dict.get('build_by_default', true)
2334 if dict.get('dbus', false)
2335 dbus_programs += exe
2336 endif
2337 if dict.get('public', false)
2338 public_programs += exe
2339 endif
2340 endif
2341
2342 if is_test
2343 type = dict.get('type', '')
2344 suite = dict.get('suite', '')
2345 if suite == ''
2346 suite = fs.name(fs.parent(dict.get('sources')[0]))
2347 if suite.startswith('sd-')
2348 suite = 'libsystemd'
2349 endif
2350 endif
2351
2352 if type == 'manual'
2353 message('@0@/@1@ is a manual test'.format(suite, name))
2354 elif type == 'unsafe' and want_tests != 'unsafe'
2355 message('@0@/@1@ is an unsafe test'.format(suite, name))
2356 elif dict.get('build_by_default')
2357 test(name, exe,
2358 env : test_env,
2359 timeout : dict.get('timeout', 30),
2360 suite : suite,
2361 is_parallel : dict.get('parallel', true))
2362 endif
2363 endif
2364
2365 if is_fuzz
2366 fuzzer_exes += exe
2367
2368 if want_tests != 'false'
2369 # Run the fuzz regression tests without any sanitizers enabled.
2370 # Additional invocations with sanitizers may get added below.
2371 fuzz_ins = fuzz_regression_tests.get(name, {})
2372 foreach directive : fuzz_ins.get('directives', [])
2373 tt = '@0@_@1@'.format(name, fs.name(directive.full_path()))
2374 if tt.substring(45) != ''
2375 error('Directive sample name is too long:', directive.full_path())
2376 endif
2377
2378 test(tt,
2379 exe,
2380 suite : 'fuzz',
2381 args : directive.full_path(),
2382 depends : directive)
2383 endforeach
2384 foreach file : fuzz_ins.get('files', [])
2385 tt = '@0@_@1@'.format(name, fs.name(file))
2386 if tt.substring(45) != ''
2387 error('Fuzz sample name is too long:', fs.name(file))
2388 endif
2389
2390 test(tt,
2391 exe,
2392 suite : 'fuzz',
2393 args : file)
2394 endforeach
2395 endif
2396 endif
2397 endforeach
2398
2399 alias_target('fuzzers', fuzzer_exes)
2400
2401 #####################################################################
2402
2403 test_dlopen = executables_by_name.get('test-dlopen')
2404
2405 foreach dict : modules
2406 name = dict.get('name')
2407 is_nss = name.startswith('nss_')
2408 is_pam = name.startswith('pam_')
2409
2410 build = true
2411 foreach cond : dict.get('conditions', [])
2412 if conf.get(cond) != 1
2413 build = false
2414 break
2415 endif
2416 endforeach
2417 if not build
2418 continue
2419 endif
2420
2421 kwargs = {}
2422 foreach key, val : dict
2423 if key in ['name', 'conditions', 'version-script']
2424 continue
2425 endif
2426 kwargs += { key : val }
2427 endforeach
2428
2429 kwargs += {
2430 'link_args' : [
2431 kwargs.get('link_args', []),
2432 '-Wl,--version-script=' + dict.get('version-script'),
2433 ],
2434 'link_depends' : [
2435 kwargs.get('link_depends', []),
2436 dict.get('version-script'),
2437 ],
2438 }
2439 foreach key, val : module_additional_kwargs
2440 kwargs += { key : [ kwargs.get(key, []), val ]}
2441 endforeach
2442
2443 lib = shared_library(
2444 name,
2445 kwargs : kwargs,
2446 )
2447
2448 if is_nss
2449 # We cannot use shared_module because it does not support version suffix.
2450 # Unfortunately shared_library insists on creating the symlink…
2451 meson.add_install_script(sh, '-c', 'rm $DESTDIR@0@/lib@1@.so'.format(libdir, name),
2452 install_tag : 'nss')
2453 endif
2454
2455 if want_tests != 'false' and (is_nss or is_pam)
2456 test('dlopen-' + name,
2457 test_dlopen,
2458 # path to dlopen must include a slash
2459 args : lib.full_path(),
2460 depends : lib,
2461 suite : is_nss ? 'nss' : 'pam')
2462 endif
2463 endforeach
2464
2465 #####################################################################
2466
2467 ukify = custom_target(
2468 'ukify',
2469 input : 'src/ukify/ukify.py',
2470 output : 'ukify',
2471 command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
2472 install : want_ukify,
2473 install_mode : 'rwxr-xr-x',
2474 install_dir : bindir)
2475 if want_ukify
2476 public_programs += ukify
2477
2478 # symlink for backwards compatibility after rename
2479 meson.add_install_script(sh, '-c',
2480 ln_s.format(bindir / 'ukify',
2481 libexecdir / 'ukify'))
2482 endif
2483
2484 #####################################################################
2485
2486 subdir('rules.d')
2487 subdir('test')
2488
2489 #####################################################################
2490
2491 subdir('docs/sysvinit')
2492 subdir('docs/var-log')
2493 subdir('hwdb.d')
2494 subdir('man')
2495 subdir('modprobe.d')
2496 subdir('network')
2497 subdir('presets')
2498 subdir('shell-completion/bash')
2499 subdir('shell-completion/zsh')
2500 subdir('sysctl.d')
2501 subdir('sysusers.d')
2502 subdir('tmpfiles.d')
2503 subdir('units')
2504
2505 install_subdir('factory/etc',
2506 install_dir : factorydir)
2507 subdir('factory/templates')
2508
2509 if install_sysconfdir
2510 install_data('xorg/50-systemd-user.sh',
2511 install_dir : xinitrcdir)
2512 endif
2513 install_data('LICENSE.GPL2',
2514 'LICENSE.LGPL2.1',
2515 'NEWS',
2516 'README',
2517 'docs/CODING_STYLE.md',
2518 'docs/DISTRO_PORTING.md',
2519 'docs/ENVIRONMENT.md',
2520 'docs/HACKING.md',
2521 'docs/TRANSIENT-SETTINGS.md',
2522 'docs/TRANSLATORS.md',
2523 'docs/UIDS-GIDS.md',
2524 install_dir : docdir)
2525
2526 install_subdir('LICENSES',
2527 install_dir : docdir)
2528
2529 install_emptydir(systemdstatedir)
2530
2531 #####################################################################
2532
2533 # Ensure that changes to the docs/ directory do not break the
2534 # basic Github pages build. But only run it in developer mode,
2535 # as it might be fragile due to changes in the tooling, and it is
2536 # not generally useful for users.
2537 jekyll = find_program('jekyll', required : false)
2538 if get_option('mode') == 'developer' and want_tests != 'false' and jekyll.found()
2539 test('github-pages',
2540 jekyll,
2541 suite : 'dist',
2542 args : ['build',
2543 '--source', project_source_root / 'docs',
2544 '--destination', project_build_root / '_site'])
2545 endif
2546
2547 #####################################################################
2548
2549 check_help = find_program('tools/check-help.sh')
2550 check_version = find_program('tools/check-version.sh')
2551
2552 foreach exec : public_programs
2553 name = fs.name(exec.full_path())
2554 if want_tests != 'false'
2555 test('check-help-' + name,
2556 check_help,
2557 suite : 'dist',
2558 args : exec.full_path(),
2559 depends: exec)
2560
2561 test('check-version-' + name,
2562 check_version,
2563 suite : 'dist',
2564 args : [exec.full_path(),
2565 meson.project_version()],
2566 depends: exec)
2567 endif
2568 endforeach
2569
2570 # Enable tests for all supported sanitizers
2571 foreach tuple : fuzz_sanitizers
2572 sanitizer = tuple[0]
2573 build = tuple[1]
2574
2575 if cc.has_link_argument('-fsanitize=@0@'.format(sanitizer))
2576 foreach fuzzer, fuzz_ins : fuzz_regression_tests
2577 name = '@0@:@1@'.format(fuzzer, sanitizer)
2578 if want_tests == 'false'
2579 message('Not compiling @0@ because tests is set to false'.format(name))
2580 continue
2581 endif
2582 if not fuzz_tests
2583 message('Not compiling @0@ because fuzz-tests is set to false'.format(name))
2584 continue
2585 endif
2586 exe = custom_target(
2587 name,
2588 output : name,
2589 depends : build,
2590 command : [ln, '-fs',
2591 build.full_path() / fuzzer,
2592 '@OUTPUT@'],
2593 build_by_default : true)
2594
2595 foreach directive : fuzz_ins.get('directives', [])
2596 test('@0@_@1@_@2@'.format(fuzzer, fs.name(directive.full_path()), sanitizer),
2597 env,
2598 suite : 'fuzz+san',
2599 env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2600 timeout : 60,
2601 args : [exe.full_path(), directive.full_path()],
2602 depends : directive)
2603 endforeach
2604 foreach file : fuzz_ins.get('files', [])
2605 test('@0@_@1@_@2@'.format(fuzzer, fs.name(file), sanitizer),
2606 env,
2607 suite : 'fuzz+san',
2608 env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2609 timeout : 60,
2610 args : [exe.full_path(), file])
2611 endforeach
2612 endforeach
2613 endif
2614 endforeach
2615
2616 #####################################################################
2617
2618 if git.found()
2619 all_files = run_command(
2620 env, '-u', 'GIT_WORK_TREE',
2621 git, '--git-dir=@0@/.git'.format(project_source_root),
2622 'ls-files', ':/*.[ch]', ':/*.cc',
2623 check : false)
2624 if all_files.returncode() == 0
2625 all_files = files(all_files.stdout().split())
2626
2627 custom_target(
2628 'tags',
2629 output : 'tags',
2630 command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)
2631 run_target(
2632 'ctags',
2633 command : [env, 'ctags', '--tag-relative=never', '-o', '@0@/tags'.format(project_source_root)] + all_files)
2634
2635 ############################################
2636
2637 if want_tests != 'false' and conf.get('BUILD_MODE_DEVELOPER') == 1
2638 test('check-includes',
2639 files('tools/check-includes.py'),
2640 args: all_files,
2641 env : ['PROJECT_SOURCE_ROOT=@0@'.format(project_source_root)],
2642 suite : 'headers')
2643 endif
2644 endif
2645
2646 ####################################################
2647
2648 git_contrib_sh = find_program('tools/git-contrib.sh')
2649 run_target(
2650 'git-contrib',
2651 command : [git_contrib_sh])
2652
2653 ####################################################
2654
2655 git_head = run_command(
2656 git, '--git-dir=@0@/.git'.format(project_source_root),
2657 'rev-parse', 'HEAD',
2658 check : false).stdout().strip()
2659 git_head_short = run_command(
2660 git, '--git-dir=@0@/.git'.format(project_source_root),
2661 'rev-parse', '--short=7', 'HEAD',
2662 check : false).stdout().strip()
2663
2664 run_target(
2665 'git-snapshot',
2666 command : [git, 'archive',
2667 '-o', '@0@/systemd-@1@.tar.gz'.format(project_source_root,
2668 git_head_short),
2669 '--prefix', 'systemd-@0@/'.format(git_head),
2670 'HEAD'])
2671 endif
2672
2673 #####################################################################
2674
2675 check_api_docs_sh = find_program('tools/check-api-docs.sh')
2676 run_target(
2677 'check-api-docs',
2678 depends : [man, libsystemd, libudev],
2679 command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
2680
2681 alias_target('update-dbus-docs', update_dbus_docs)
2682 alias_target('update-man-rules', update_man_rules)
2683
2684 if not meson.is_cross_build()
2685 custom_target(
2686 'export-dbus-interfaces',
2687 output : fs.name(dbus_interfaces_dir),
2688 install : dbus_interfaces_dir != 'no',
2689 install_dir : fs.parent(dbus_interfaces_dir),
2690 command : [export_dbus_interfaces_py, '@OUTPUT@', dbus_programs])
2691 endif
2692
2693 #####################################################################
2694
2695 alt_time_epoch = run_command('date', '-Is', '-u', '-d', '@@0@'.format(time_epoch),
2696 check : true).stdout().strip()
2697
2698 summary({
2699 'split bin-sbin' : split_bin,
2700 'prefix directory' : prefixdir,
2701 'sysconf directory' : sysconfdir,
2702 'include directory' : includedir,
2703 'lib directory' : libdir,
2704 'SysV init scripts' : sysvinit_path,
2705 'SysV rc?.d directories' : sysvrcnd_path,
2706 'PAM modules directory' : pamlibdir,
2707 'PAM configuration directory' : pamconfdir,
2708 'ssh server configuration directory' : sshdconfdir,
2709 'ssh client configuration directory' : sshconfdir,
2710 'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
2711 'RPM macros directory' : rpmmacrosdir,
2712 'modprobe.d directory' : modprobedir,
2713 'D-Bus policy directory' : dbuspolicydir,
2714 'D-Bus session directory' : dbussessionservicedir,
2715 'D-Bus system directory' : dbussystemservicedir,
2716 'D-Bus interfaces directory' : dbus_interfaces_dir,
2717 'bash completions directory' : bashcompletiondir,
2718 'zsh completions directory' : zshcompletiondir,
2719 'private shared lib version tag' : shared_lib_tag,
2720 'extra start script' : get_option('rc-local'),
2721 'debug shell' : '@0@ @ @1@'.format(get_option('debug-shell'),
2722 get_option('debug-tty')),
2723 'system UIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
2724 conf.get('SYSTEM_ALLOC_UID_MIN')),
2725 'system GIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
2726 conf.get('SYSTEM_ALLOC_GID_MIN')),
2727 'dynamic UIDs' : '@0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
2728 'container UID bases' : '@0@…@1@'.format(container_uid_base_min, container_uid_base_max),
2729 'static UID/GID allocations' : ' '.join(static_ugids),
2730 '/dev/kvm access mode' : get_option('dev-kvm-mode'),
2731 'render group access mode' : get_option('group-render-mode'),
2732 'certificate root directory' : get_option('certificate-root'),
2733 'support URL' : support_url,
2734 'nobody user name' : nobody_user,
2735 'nobody group name' : nobody_group,
2736 'fallback hostname' : get_option('fallback-hostname'),
2737 'default compression method' : compression,
2738 'default DNSSEC mode' : default_dnssec,
2739 'default DNS-over-TLS mode' : default_dns_over_tls,
2740 'default mDNS mode' : default_mdns,
2741 'default LLMNR mode' : default_llmnr,
2742 'default DNS servers' : dns_servers.split(' '),
2743 'default NTP servers' : ntp_servers.split(' '),
2744 'default cgroup hierarchy' : default_hierarchy,
2745 'default net.naming-scheme value' : default_net_naming_scheme,
2746 'default KillUserProcesses value' : kill_user_processes,
2747 'default locale' : default_locale,
2748 'default nspawn locale' : nspawn_locale,
2749 'default status unit format' : status_unit_format_default,
2750 'default user $PATH' :
2751 default_user_path != '' ? default_user_path : '(same as system services)',
2752 'systemd service watchdog' : service_watchdog == '' ? 'disabled' : service_watchdog,
2753 'time epoch' : '@0@ (@1@)'.format(time_epoch, alt_time_epoch)})
2754
2755 # TODO:
2756 # CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
2757 # CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
2758 # LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
2759
2760 found = []
2761 missing = []
2762
2763 foreach tuple : [
2764 # dependencies
2765 ['ACL'],
2766 ['AUDIT'],
2767 ['AppArmor'],
2768 ['IMA'],
2769 ['PAM'],
2770 ['SECCOMP'],
2771 ['SELinux'],
2772 ['SMACK'],
2773 ['blkid'],
2774 ['elfutils'],
2775 ['gcrypt'],
2776 ['gnutls'],
2777 ['libbpf'],
2778 ['libcryptsetup'],
2779 ['libcryptsetup-plugins'],
2780 ['libcurl'],
2781 ['libfdisk'],
2782 ['libfido2'],
2783 ['libidn'],
2784 ['libidn2'],
2785 ['libiptc'],
2786 ['microhttpd'],
2787 ['openssl'],
2788 ['p11kit'],
2789 ['passwdqc'],
2790 ['pcre2'],
2791 ['pwquality'],
2792 ['qrencode'],
2793 ['tpm2'],
2794 ['xkbcommon'],
2795
2796 # compression libs
2797 ['zstd'],
2798 ['lz4'],
2799 ['xz'],
2800 ['zlib'],
2801 ['bzip2'],
2802
2803 # components
2804 ['backlight'],
2805 ['binfmt'],
2806 ['bootloader'],
2807 ['bpf-framework', conf.get('BPF_FRAMEWORK') == 1],
2808 ['coredump'],
2809 ['efi'],
2810 ['environment.d'],
2811 ['firstboot'],
2812 ['hibernate'],
2813 ['homed'],
2814 ['hostnamed'],
2815 ['hwdb'],
2816 ['importd'],
2817 ['initrd'],
2818 ['kernel-install'],
2819 ['localed'],
2820 ['logind'],
2821 ['machined'],
2822 ['networkd'],
2823 ['nss-myhostname'],
2824 ['nss-mymachines'],
2825 ['nss-resolve'],
2826 ['nss-systemd'],
2827 ['oomd'],
2828 ['portabled'],
2829 ['pstore'],
2830 ['quotacheck'],
2831 ['randomseed'],
2832 ['repart'],
2833 ['resolve'],
2834 ['rfkill'],
2835 ['sysext'],
2836 ['systemd-analyze', conf.get('ENABLE_ANALYZE') == 1],
2837 ['sysupdate'],
2838 ['sysusers'],
2839 ['storagetm'],
2840 ['timedated'],
2841 ['timesyncd'],
2842 ['tmpfiles'],
2843 ['userdb'],
2844 ['vconsole'],
2845 ['vmspawn'],
2846 ['xdg-autostart'],
2847
2848 # optional features
2849 ['dmi'],
2850 ['idn'],
2851 ['polkit'],
2852 ['nscd'],
2853 ['legacy-pkla', install_polkit_pkla],
2854 ['kmod'],
2855 ['xenctrl'],
2856 ['dbus'],
2857 ['glib'],
2858 ['tpm'],
2859 ['man pages', want_man],
2860 ['html pages', want_html],
2861 ['man page indices', want_man and have_lxml],
2862 ['SysV compat'],
2863 ['compat-mutable-uid-boundaries'],
2864 ['utmp'],
2865 ['ldconfig'],
2866 ['adm group', get_option('adm-group')],
2867 ['wheel group', get_option('wheel-group')],
2868 ['gshadow'],
2869 ['debug hashmap'],
2870 ['debug mmap cache'],
2871 ['debug siphash'],
2872 ['trace logging', conf.get('LOG_TRACE') == 1],
2873 ['slow tests', slow_tests],
2874 ['fuzz tests', fuzz_tests],
2875 ['install tests', install_tests],
2876 ['link-udev-shared', get_option('link-udev-shared')],
2877 ['link-systemctl-shared', get_option('link-systemctl-shared')],
2878 ['link-networkd-shared', get_option('link-networkd-shared')],
2879 ['link-timesyncd-shared', get_option('link-timesyncd-shared')],
2880 ['link-journalctl-shared', get_option('link-journalctl-shared')],
2881 ['link-boot-shared', get_option('link-boot-shared')],
2882 ['link-portabled-shared', get_option('link-portabled-shared')],
2883 ['first-boot-full-preset'],
2884 ['fexecve'],
2885 ['standalone-binaries', get_option('standalone-binaries')],
2886 ['coverage', get_option('b_coverage')],
2887 ]
2888
2889 if tuple.length() >= 2
2890 cond = tuple[1]
2891 else
2892 ident1 = 'HAVE_' + tuple[0].underscorify().to_upper()
2893 ident2 = 'ENABLE_' + tuple[0].underscorify().to_upper()
2894 cond = conf.get(ident1, 0) == 1 or conf.get(ident2, 0) == 1
2895 endif
2896 if cond
2897 found += tuple[0]
2898 else
2899 missing += tuple[0]
2900 endif
2901 endforeach
2902
2903 if static_libsystemd == 'false'
2904 missing += 'static-libsystemd'
2905 else
2906 found += 'static-libsystemd(@0@)'.format(static_libsystemd)
2907 endif
2908
2909 if static_libudev == 'false'
2910 missing += 'static-libudev'
2911 else
2912 found += 'static-libudev(@0@)'.format(static_libudev)
2913 endif
2914
2915 if conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and conf.get('PREFER_OPENSSL') == 1
2916 found += 'cryptolib(openssl)'
2917 elif conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1
2918 found += 'cryptolib(gcrypt)'
2919 else
2920 missing += 'cryptolib'
2921 endif
2922
2923 if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
2924 found += 'DNS-over-TLS(gnutls)'
2925 elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
2926 found += 'DNS-over-TLS(openssl)'
2927 else
2928 missing += 'DNS-over-TLS'
2929 endif
2930
2931 summary({
2932 'enabled' : ', '.join(found),
2933 'disabled' : ', '.join(missing)},
2934 section : 'Features')