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