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