]> git.ipfire.org Git - thirdparty/systemd.git/blob - meson.build
Merge pull request #30827 from poettering/network-generator-creds
[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 pefile = pymod.find_installation('python3', required: false, modules : ['pefile'])
1815
1816 want_ukify = get_option('ukify').require(python_39 and (want_tests != 'true' or pefile.found()), error_message : 'Python >= 3.9 and pefile required').allowed()
1817 conf.set10('ENABLE_UKIFY', want_ukify)
1818
1819 #####################################################################
1820
1821 check_version_history_py = find_program('tools/check-version-history.py')
1822 elf2efi_py = find_program('tools/elf2efi.py')
1823 export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
1824 generate_gperfs = find_program('tools/generate-gperfs.py')
1825 make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py')
1826 make_directive_index_py = find_program('tools/make-directive-index.py')
1827 sync_docs_py = find_program('tools/sync-docs.py')
1828 make_man_index_py = find_program('tools/make-man-index.py')
1829 meson_render_jinja2 = find_program('tools/meson-render-jinja2.py')
1830 update_dbus_docs_py = find_program('tools/update-dbus-docs.py')
1831 update_hwdb_autosuspend_sh = find_program('tools/update-hwdb-autosuspend.sh')
1832 update_hwdb_sh = find_program('tools/update-hwdb.sh')
1833 update_man_rules_py = find_program('tools/update-man-rules.py')
1834 update_syscall_tables_sh = find_program('tools/update-syscall-tables.sh')
1835 xml_helper_py = find_program('tools/xml_helper.py')
1836
1837 #####################################################################
1838
1839 version_tag = get_option('version-tag')
1840 version_h = vcs_tag(
1841 input : 'src/version/version.h.in',
1842 output : 'version.h',
1843 command: [project_source_root / 'tools/meson-vcs-tag.sh',
1844 project_source_root,
1845 meson.project_version(),
1846 version_tag,
1847 ])
1848
1849 shared_lib_tag = get_option('shared-lib-tag')
1850 if shared_lib_tag == ''
1851 shared_lib_tag = meson.project_version()
1852 endif
1853
1854 #####################################################################
1855
1856 if get_option('b_coverage')
1857 userspace_c_args += ['-include', 'src/basic/coverage.h']
1858 endif
1859
1860 #####################################################################
1861
1862 config_h = configure_file(
1863 output : 'config.h',
1864 configuration : conf)
1865
1866 userspace_c_args += ['-include', 'config.h']
1867
1868 jinja2_cmdline = [meson_render_jinja2, config_h, version_h]
1869
1870 userspace = declare_dependency(
1871 compile_args : userspace_c_args,
1872 link_args : userspace_c_ld_args,
1873 sources : version_h,
1874 )
1875
1876 man_page_depends = []
1877
1878 #####################################################################
1879
1880 simple_tests = []
1881 libsystemd_tests = []
1882 simple_fuzzers = []
1883 catalogs = []
1884 modules = [] # nss, pam, and other plugins
1885 executables = []
1886 executables_by_name = {}
1887 fuzzer_exes = []
1888
1889 # binaries that have --help and are intended for use by humans,
1890 # usually, but not always, installed in /bin.
1891 public_programs = []
1892
1893 # D-Bus introspection XML export
1894 dbus_programs = []
1895
1896 # A list of boot stubs. Required for testing of ukify.
1897 boot_stubs = []
1898
1899 build_dir_include = include_directories('.')
1900
1901 basic_includes = include_directories(
1902 'src/basic',
1903 'src/fundamental',
1904 'src/systemd',
1905 '.')
1906
1907 libsystemd_includes = [basic_includes, include_directories(
1908 'src/libsystemd/sd-bus',
1909 'src/libsystemd/sd-device',
1910 'src/libsystemd/sd-event',
1911 'src/libsystemd/sd-hwdb',
1912 'src/libsystemd/sd-id128',
1913 'src/libsystemd/sd-journal',
1914 'src/libsystemd/sd-netlink',
1915 'src/libsystemd/sd-network',
1916 'src/libsystemd/sd-resolve')]
1917
1918 includes = [libsystemd_includes, include_directories('src/shared')]
1919
1920 subdir('po')
1921 subdir('catalog')
1922 subdir('src/fundamental')
1923 subdir('src/basic')
1924 subdir('src/libsystemd')
1925 subdir('src/shared')
1926 subdir('src/libudev')
1927
1928 libsystemd = shared_library(
1929 'systemd',
1930 version : libsystemd_version,
1931 include_directories : libsystemd_includes,
1932 link_args : ['-shared',
1933 '-Wl,--version-script=' + libsystemd_sym_path],
1934 link_with : [libbasic,
1935 libbasic_gcrypt,
1936 libbasic_compress],
1937 link_whole : [libsystemd_static],
1938 dependencies : [librt,
1939 threads,
1940 userspace],
1941 link_depends : libsystemd_sym,
1942 install : true,
1943 install_tag: 'libsystemd',
1944 install_dir : libdir)
1945
1946 alias_target('libsystemd', libsystemd)
1947
1948 install_libsystemd_static = static_library(
1949 'systemd',
1950 libsystemd_sources,
1951 basic_sources,
1952 basic_gcrypt_sources,
1953 basic_compress_sources,
1954 fundamental_sources,
1955 include_directories : libsystemd_includes,
1956 build_by_default : static_libsystemd != 'false',
1957 install : static_libsystemd != 'false',
1958 install_tag: 'libsystemd',
1959 install_dir : libdir,
1960 pic : static_libsystemd_pic,
1961 dependencies : [libblkid,
1962 libcap,
1963 libdl,
1964 libgcrypt,
1965 liblz4,
1966 libmount,
1967 libopenssl,
1968 librt,
1969 libxz,
1970 libzstd,
1971 threads,
1972 userspace],
1973 c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
1974
1975 libudev = shared_library(
1976 'udev',
1977 version : libudev_version,
1978 include_directories : includes,
1979 link_args : ['-shared',
1980 '-Wl,--version-script=' + libudev_sym_path],
1981 link_with : [libsystemd_static, libshared_static],
1982 link_whole : libudev_basic,
1983 dependencies : [threads,
1984 userspace],
1985 link_depends : libudev_sym,
1986 install : true,
1987 install_tag: 'libudev',
1988 install_dir : libdir)
1989
1990 alias_target('libudev', libudev)
1991
1992 install_libudev_static = static_library(
1993 'udev',
1994 basic_sources,
1995 fundamental_sources,
1996 shared_sources,
1997 libsystemd_sources,
1998 libudev_sources,
1999 include_directories : includes,
2000 build_by_default : static_libudev != 'false',
2001 install : static_libudev != 'false',
2002 install_tag: 'libudev',
2003 install_dir : libdir,
2004 link_depends : libudev_sym,
2005 dependencies : [libmount,
2006 libshared_deps,
2007 userspace],
2008 c_args : static_libudev_pic ? [] : ['-fno-PIC'],
2009 pic : static_libudev_pic)
2010
2011 #####################################################################
2012
2013 runtest_env = custom_target(
2014 'systemd-runtest.env',
2015 output : 'systemd-runtest.env',
2016 command : [sh, '-c',
2017 '{ echo SYSTEMD_TEST_DATA=@0@; echo SYSTEMD_CATALOG_DIR=@1@; } >@OUTPUT@'.format(
2018 project_source_root / 'test',
2019 project_build_root / 'catalog')],
2020 depends : catalogs,
2021 build_by_default : true)
2022
2023 test_cflags = ['-DTEST_CODE=1']
2024 # We intentionally do not do inline initializations with definitions for a
2025 # bunch of _cleanup_ variables in tests, to ensure valgrind is triggered if we
2026 # use the variable unexpectedly. This triggers a lot of maybe-uninitialized
2027 # false positives when the combination of -O2 and -flto is used. Suppress them.
2028 if '-O2' in c_args and '-flto=auto' in c_args
2029 test_cflags += cc.first_supported_argument('-Wno-maybe-uninitialized')
2030 endif
2031
2032 #####################################################################
2033
2034 executable_template = {
2035 'include_directories' : includes,
2036 'link_with' : libshared,
2037 'install_rpath' : pkglibdir,
2038 'install' : true,
2039 }
2040
2041 generator_template = executable_template + {
2042 'install_dir' : systemgeneratordir,
2043 }
2044
2045 libexec_template = executable_template + {
2046 'install_dir' : libexecdir,
2047 }
2048
2049 executable_additional_kwargs = {
2050 'dependencies' : userspace,
2051 }
2052
2053 test_template = executable_template + {
2054 'build_by_default' : want_tests != 'false',
2055 'install' : install_tests,
2056 'install_dir' : unittestsdir,
2057 }
2058
2059 test_additional_kwargs = {
2060 'c_args' : test_cflags,
2061 'link_depends' : runtest_env,
2062 }
2063
2064 fuzz_template = executable_template + {
2065 'build_by_default' : fuzzer_build,
2066 'install' : false,
2067 }
2068
2069 if want_ossfuzz or (want_libfuzzer and fuzzing_engine.found())
2070 fuzz_additional_kwargs = {
2071 'dependencies' : fuzzing_engine,
2072 }
2073 elif want_libfuzzer and not fuzzing_engine.found()
2074 fuzz_additional_kwargs = {
2075 'link_args' : ['-fsanitize=fuzzer'],
2076 }
2077 else
2078 fuzz_additional_kwargs = {
2079 'sources' : files('src/fuzz/fuzz-main.c'),
2080 }
2081 endif
2082 fuzz_additional_kwargs += {
2083 'include_directories' : include_directories('src/fuzz'),
2084 'c_args' : test_cflags,
2085 }
2086
2087 nss_template = {
2088 'version' : '2',
2089 'include_directories' : includes,
2090 # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
2091 'link_args' : ['-z', 'nodelete'],
2092 'link_with' : [
2093 libsystemd_static,
2094 libshared_static,
2095 libbasic,
2096 ],
2097 'dependencies' : [
2098 librt,
2099 threads,
2100 ],
2101 'install' : true,
2102 'install_tag' : 'nss',
2103 'install_dir' : libdir,
2104 }
2105
2106 pam_template = {
2107 'name_prefix' : '',
2108 'include_directories' : includes,
2109 'link_with' : [
2110 libsystemd_static,
2111 libshared_static,
2112 ],
2113 'dependencies' : [
2114 libpam_misc,
2115 libpam,
2116 threads,
2117 ],
2118 'install' : true,
2119 'install_tag' : 'pam',
2120 'install_dir' : pamlibdir,
2121 }
2122
2123 module_additional_kwargs = {
2124 'link_args' : ['-shared'],
2125 'dependencies' : userspace,
2126 }
2127
2128 #####################################################################
2129
2130 # systemd-analyze requires 'libcore'
2131 subdir('src/core')
2132 # systemd-networkd requires 'libsystemd_network'
2133 subdir('src/libsystemd-network')
2134 # hwdb requires 'udev_link_with' and 'udev_rpath'
2135 subdir('src/udev')
2136
2137 subdir('src/ac-power')
2138 subdir('src/analyze')
2139 subdir('src/ask-password')
2140 subdir('src/backlight')
2141 subdir('src/battery-check')
2142 subdir('src/binfmt')
2143 subdir('src/boot')
2144 subdir('src/boot/efi')
2145 subdir('src/busctl')
2146 subdir('src/cgls')
2147 subdir('src/cgroups-agent')
2148 subdir('src/cgtop')
2149 subdir('src/coredump')
2150 subdir('src/creds')
2151 subdir('src/cryptenroll')
2152 subdir('src/cryptsetup')
2153 subdir('src/debug-generator')
2154 subdir('src/delta')
2155 subdir('src/detect-virt')
2156 subdir('src/dissect')
2157 subdir('src/environment-d-generator')
2158 subdir('src/escape')
2159 subdir('src/firstboot')
2160 subdir('src/fsck')
2161 subdir('src/fstab-generator')
2162 subdir('src/getty-generator')
2163 subdir('src/gpt-auto-generator')
2164 subdir('src/hibernate-resume')
2165 subdir('src/home')
2166 subdir('src/hostname')
2167 subdir('src/hwdb')
2168 subdir('src/id128')
2169 subdir('src/import')
2170 subdir('src/initctl')
2171 subdir('src/integritysetup')
2172 subdir('src/journal')
2173 subdir('src/journal-remote')
2174 subdir('src/kernel-install')
2175 subdir('src/locale')
2176 subdir('src/login')
2177 subdir('src/machine')
2178 subdir('src/machine-id-setup')
2179 subdir('src/modules-load')
2180 subdir('src/mount')
2181 subdir('src/network')
2182 subdir('src/notify')
2183 subdir('src/nspawn')
2184 subdir('src/nss-myhostname')
2185 subdir('src/nss-mymachines')
2186 subdir('src/nss-resolve')
2187 subdir('src/nss-systemd')
2188 subdir('src/oom')
2189 subdir('src/partition')
2190 subdir('src/path')
2191 subdir('src/pcrextend')
2192 subdir('src/pcrlock')
2193 subdir('src/portable')
2194 subdir('src/pstore')
2195 subdir('src/quotacheck')
2196 subdir('src/random-seed')
2197 subdir('src/rc-local-generator')
2198 subdir('src/remount-fs')
2199 subdir('src/reply-password')
2200 subdir('src/resolve')
2201 subdir('src/rfkill')
2202 subdir('src/rpm')
2203 subdir('src/run')
2204 subdir('src/run-generator')
2205 subdir('src/shutdown')
2206 subdir('src/sleep')
2207 subdir('src/socket-activate')
2208 subdir('src/socket-proxy')
2209 subdir('src/stdio-bridge')
2210 subdir('src/sulogin-shell')
2211 subdir('src/sysctl')
2212 subdir('src/sysext')
2213 subdir('src/system-update-generator')
2214 subdir('src/systemctl')
2215 subdir('src/sysupdate')
2216 subdir('src/sysusers')
2217 subdir('src/sysv-generator')
2218 subdir('src/storagetm')
2219 subdir('src/timedate')
2220 subdir('src/timesync')
2221 subdir('src/tmpfiles')
2222 subdir('src/tpm2-setup')
2223 subdir('src/tty-ask-password-agent')
2224 subdir('src/update-done')
2225 subdir('src/update-utmp')
2226 subdir('src/user-sessions')
2227 subdir('src/userdb')
2228 subdir('src/varlinkctl')
2229 subdir('src/vconsole')
2230 subdir('src/veritysetup')
2231 subdir('src/vmspawn')
2232 subdir('src/volatile-root')
2233 subdir('src/vpick')
2234 subdir('src/xdg-autostart-generator')
2235
2236 subdir('src/systemd')
2237
2238 subdir('src/test')
2239 subdir('src/fuzz')
2240 subdir('src/ukify/test') # needs to be last for test_env variable
2241 subdir('test/fuzz')
2242
2243 subdir('mime')
2244
2245 alias_target('devel', libsystemd_pc, libudev_pc, systemd_pc, udev_pc)
2246
2247 #####################################################################
2248
2249 foreach test : simple_tests
2250 executables += test_template + { 'sources' : [test] }
2251 endforeach
2252
2253 foreach test : libsystemd_tests
2254 executables += test_template + test
2255 endforeach
2256
2257 foreach fuzzer : simple_fuzzers
2258 executables += fuzz_template + { 'sources' : [fuzzer] }
2259 endforeach
2260
2261 foreach dict : executables
2262 name = dict.get('name', '')
2263 if name == ''
2264 name = fs.stem(dict.get('sources')[0])
2265 assert(name.split('-')[0] in ['test', 'fuzz'])
2266 endif
2267
2268 is_test = name.startswith('test-')
2269 is_fuzz = name.startswith('fuzz-')
2270
2271 build = true
2272 foreach cond : dict.get('conditions', [])
2273 if conf.get(cond) != 1
2274 build = false
2275 break
2276 endif
2277 endforeach
2278 if not build
2279 continue
2280 endif
2281
2282 kwargs = {}
2283 foreach key, val : dict
2284 if key in ['name', 'dbus', 'public', 'conditions',
2285 'type', 'suite', 'timeout', 'parallel']
2286 continue
2287 endif
2288
2289 kwargs += { key : val }
2290 endforeach
2291
2292 foreach key, val : executable_additional_kwargs
2293 kwargs += { key : [ kwargs.get(key, []), val ]}
2294 endforeach
2295
2296 if is_test
2297 kwargs += { 'install_dir' : kwargs.get('install_dir') / dict.get('type', '') }
2298 foreach key, val : test_additional_kwargs
2299 kwargs += { key : [ kwargs.get(key, []), val ] }
2300 endforeach
2301 endif
2302
2303 if is_fuzz
2304 foreach key, val : fuzz_additional_kwargs
2305 kwargs += { key : [ kwargs.get(key, []), val ] }
2306 endforeach
2307 endif
2308
2309 exe = executable(
2310 name,
2311 kwargs : kwargs,
2312 )
2313
2314 executables_by_name += { name : exe }
2315
2316 if dict.get('build_by_default', true)
2317 if dict.get('dbus', false)
2318 dbus_programs += exe
2319 endif
2320 if dict.get('public', false)
2321 public_programs += exe
2322 endif
2323 endif
2324
2325 if is_test
2326 type = dict.get('type', '')
2327 suite = dict.get('suite', '')
2328 if suite == ''
2329 suite = fs.name(fs.parent(dict.get('sources')[0]))
2330 if suite.startswith('sd-')
2331 suite = 'libsystemd'
2332 endif
2333 endif
2334
2335 if type == 'manual'
2336 message('@0@/@1@ is a manual test'.format(suite, name))
2337 elif type == 'unsafe' and want_tests != 'unsafe'
2338 message('@0@/@1@ is an unsafe test'.format(suite, name))
2339 elif dict.get('build_by_default')
2340 test(name, exe,
2341 env : test_env,
2342 timeout : dict.get('timeout', 30),
2343 suite : suite,
2344 is_parallel : dict.get('parallel', true))
2345 endif
2346 endif
2347
2348 if is_fuzz
2349 fuzzer_exes += exe
2350
2351 if want_tests != 'false'
2352 # Run the fuzz regression tests without any sanitizers enabled.
2353 # Additional invocations with sanitizers may get added below.
2354 fuzz_ins = fuzz_regression_tests.get(name, {})
2355 foreach directive : fuzz_ins.get('directives', [])
2356 tt = '@0@_@1@'.format(name, fs.name(directive.full_path()))
2357 if tt.substring(45) != ''
2358 error('Directive sample name is too long:', directive.full_path())
2359 endif
2360
2361 test(tt,
2362 exe,
2363 suite : 'fuzz',
2364 args : directive.full_path(),
2365 depends : directive)
2366 endforeach
2367 foreach file : fuzz_ins.get('files', [])
2368 tt = '@0@_@1@'.format(name, fs.name(file))
2369 if tt.substring(45) != ''
2370 error('Fuzz sample name is too long:', fs.name(file))
2371 endif
2372
2373 test(tt,
2374 exe,
2375 suite : 'fuzz',
2376 args : file)
2377 endforeach
2378 endif
2379 endif
2380 endforeach
2381
2382 alias_target('fuzzers', fuzzer_exes)
2383
2384 #####################################################################
2385
2386 test_dlopen = executables_by_name.get('test-dlopen')
2387
2388 foreach dict : modules
2389 name = dict.get('name')
2390 is_nss = name.startswith('nss_')
2391 is_pam = name.startswith('pam_')
2392
2393 build = true
2394 foreach cond : dict.get('conditions', [])
2395 if conf.get(cond) != 1
2396 build = false
2397 break
2398 endif
2399 endforeach
2400 if not build
2401 continue
2402 endif
2403
2404 kwargs = {}
2405 foreach key, val : dict
2406 if key in ['name', 'conditions', 'version-script']
2407 continue
2408 endif
2409 kwargs += { key : val }
2410 endforeach
2411
2412 kwargs += {
2413 'link_args' : [
2414 kwargs.get('link_args', []),
2415 '-Wl,--version-script=' + dict.get('version-script'),
2416 ],
2417 'link_depends' : [
2418 kwargs.get('link_depends', []),
2419 dict.get('version-script'),
2420 ],
2421 }
2422 foreach key, val : module_additional_kwargs
2423 kwargs += { key : [ kwargs.get(key, []), val ]}
2424 endforeach
2425
2426 lib = shared_library(
2427 name,
2428 kwargs : kwargs,
2429 )
2430
2431 if is_nss
2432 # We cannot use shared_module because it does not support version suffix.
2433 # Unfortunately shared_library insists on creating the symlink…
2434 meson.add_install_script(sh, '-c', 'rm $DESTDIR@0@/lib@1@.so'.format(libdir, name),
2435 install_tag : 'nss')
2436 endif
2437
2438 if want_tests != 'false' and (is_nss or is_pam)
2439 test('dlopen-' + name,
2440 test_dlopen,
2441 # path to dlopen must include a slash
2442 args : lib.full_path(),
2443 depends : lib,
2444 suite : is_nss ? 'nss' : 'pam')
2445 endif
2446 endforeach
2447
2448 #####################################################################
2449
2450 ukify = custom_target(
2451 'ukify',
2452 input : 'src/ukify/ukify.py',
2453 output : 'ukify',
2454 command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
2455 install : want_ukify,
2456 install_mode : 'rwxr-xr-x',
2457 install_dir : bindir)
2458 if want_ukify
2459 public_programs += ukify
2460
2461 # symlink for backwards compatibility after rename
2462 meson.add_install_script(sh, '-c',
2463 ln_s.format(bindir / 'ukify',
2464 libexecdir / 'ukify'))
2465 endif
2466
2467 #####################################################################
2468
2469 subdir('rules.d')
2470 subdir('test')
2471
2472 #####################################################################
2473
2474 subdir('docs/sysvinit')
2475 subdir('docs/var-log')
2476 subdir('hwdb.d')
2477 subdir('man')
2478 subdir('modprobe.d')
2479 subdir('network')
2480 subdir('presets')
2481 subdir('shell-completion/bash')
2482 subdir('shell-completion/zsh')
2483 subdir('sysctl.d')
2484 subdir('sysusers.d')
2485 subdir('tmpfiles.d')
2486 subdir('units')
2487
2488 install_subdir('factory/etc',
2489 install_dir : factorydir)
2490 subdir('factory/templates')
2491
2492 if install_sysconfdir
2493 install_data('xorg/50-systemd-user.sh',
2494 install_dir : xinitrcdir)
2495 endif
2496 install_data('LICENSE.GPL2',
2497 'LICENSE.LGPL2.1',
2498 'NEWS',
2499 'README',
2500 'docs/CODING_STYLE.md',
2501 'docs/DISTRO_PORTING.md',
2502 'docs/ENVIRONMENT.md',
2503 'docs/HACKING.md',
2504 'docs/TRANSIENT-SETTINGS.md',
2505 'docs/TRANSLATORS.md',
2506 'docs/UIDS-GIDS.md',
2507 install_dir : docdir)
2508
2509 install_subdir('LICENSES',
2510 install_dir : docdir)
2511
2512 install_emptydir(systemdstatedir)
2513
2514 #####################################################################
2515
2516 # Ensure that changes to the docs/ directory do not break the
2517 # basic Github pages build. But only run it in developer mode,
2518 # as it might be fragile due to changes in the tooling, and it is
2519 # not generally useful for users.
2520 jekyll = find_program('jekyll', required : false)
2521 if get_option('mode') == 'developer' and want_tests != 'false' and jekyll.found()
2522 test('github-pages',
2523 jekyll,
2524 suite : 'dist',
2525 args : ['build',
2526 '--source', project_source_root / 'docs',
2527 '--destination', project_build_root / '_site'])
2528 endif
2529
2530 #####################################################################
2531
2532 check_help = find_program('tools/check-help.sh')
2533 check_version = find_program('tools/check-version.sh')
2534
2535 foreach exec : public_programs
2536 name = fs.name(exec.full_path())
2537 if want_tests != 'false'
2538 test('check-help-' + name,
2539 check_help,
2540 suite : 'dist',
2541 args : exec.full_path(),
2542 depends: exec)
2543
2544 test('check-version-' + name,
2545 check_version,
2546 suite : 'dist',
2547 args : [exec.full_path(),
2548 meson.project_version()],
2549 depends: exec)
2550 endif
2551 endforeach
2552
2553 # Enable tests for all supported sanitizers
2554 foreach tuple : fuzz_sanitizers
2555 sanitizer = tuple[0]
2556 build = tuple[1]
2557
2558 if cc.has_link_argument('-fsanitize=@0@'.format(sanitizer))
2559 foreach fuzzer, fuzz_ins : fuzz_regression_tests
2560 name = '@0@:@1@'.format(fuzzer, sanitizer)
2561 if want_tests == 'false'
2562 message('Not compiling @0@ because tests is set to false'.format(name))
2563 continue
2564 endif
2565 if not fuzz_tests
2566 message('Not compiling @0@ because fuzz-tests is set to false'.format(name))
2567 continue
2568 endif
2569 exe = custom_target(
2570 name,
2571 output : name,
2572 depends : build,
2573 command : [ln, '-fs',
2574 build.full_path() / fuzzer,
2575 '@OUTPUT@'],
2576 build_by_default : true)
2577
2578 foreach directive : fuzz_ins.get('directives', [])
2579 test('@0@_@1@_@2@'.format(fuzzer, fs.name(directive.full_path()), sanitizer),
2580 env,
2581 suite : 'fuzz+san',
2582 env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2583 timeout : 60,
2584 args : [exe.full_path(), directive.full_path()],
2585 depends : directive)
2586 endforeach
2587 foreach file : fuzz_ins.get('files', [])
2588 test('@0@_@1@_@2@'.format(fuzzer, fs.name(file), sanitizer),
2589 env,
2590 suite : 'fuzz+san',
2591 env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
2592 timeout : 60,
2593 args : [exe.full_path(), file])
2594 endforeach
2595 endforeach
2596 endif
2597 endforeach
2598
2599 #####################################################################
2600
2601 if git.found()
2602 all_files = run_command(
2603 env, '-u', 'GIT_WORK_TREE',
2604 git, '--git-dir=@0@/.git'.format(project_source_root),
2605 'ls-files', ':/*.[ch]', ':/*.cc',
2606 check : false)
2607 if all_files.returncode() == 0
2608 all_files = files(all_files.stdout().split())
2609
2610 custom_target(
2611 'tags',
2612 output : 'tags',
2613 command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)
2614 run_target(
2615 'ctags',
2616 command : [env, 'ctags', '--tag-relative=never', '-o', '@0@/tags'.format(project_source_root)] + all_files)
2617
2618 ############################################
2619
2620 if want_tests != 'false' and conf.get('BUILD_MODE_DEVELOPER') == 1
2621 test('check-includes',
2622 files('tools/check-includes.py'),
2623 args: all_files,
2624 env : ['PROJECT_SOURCE_ROOT=@0@'.format(project_source_root)],
2625 suite : 'headers')
2626 endif
2627 endif
2628
2629 ####################################################
2630
2631 git_contrib_sh = find_program('tools/git-contrib.sh')
2632 run_target(
2633 'git-contrib',
2634 command : [git_contrib_sh])
2635
2636 ####################################################
2637
2638 git_head = run_command(
2639 git, '--git-dir=@0@/.git'.format(project_source_root),
2640 'rev-parse', 'HEAD',
2641 check : false).stdout().strip()
2642 git_head_short = run_command(
2643 git, '--git-dir=@0@/.git'.format(project_source_root),
2644 'rev-parse', '--short=7', 'HEAD',
2645 check : false).stdout().strip()
2646
2647 run_target(
2648 'git-snapshot',
2649 command : [git, 'archive',
2650 '-o', '@0@/systemd-@1@.tar.gz'.format(project_source_root,
2651 git_head_short),
2652 '--prefix', 'systemd-@0@/'.format(git_head),
2653 'HEAD'])
2654 endif
2655
2656 #####################################################################
2657
2658 check_api_docs_sh = find_program('tools/check-api-docs.sh')
2659 run_target(
2660 'check-api-docs',
2661 depends : [man, libsystemd, libudev],
2662 command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
2663
2664 alias_target('update-dbus-docs', update_dbus_docs)
2665 alias_target('update-man-rules', update_man_rules)
2666
2667 if not meson.is_cross_build()
2668 custom_target(
2669 'export-dbus-interfaces',
2670 output : fs.name(dbus_interfaces_dir),
2671 install : dbus_interfaces_dir != 'no',
2672 install_dir : fs.parent(dbus_interfaces_dir),
2673 command : [export_dbus_interfaces_py, '@OUTPUT@', dbus_programs])
2674 endif
2675
2676 #####################################################################
2677
2678 alt_time_epoch = run_command('date', '-Is', '-u', '-d', '@@0@'.format(time_epoch),
2679 check : true).stdout().strip()
2680
2681 summary({
2682 'split bin-sbin' : split_bin,
2683 'prefix directory' : prefixdir,
2684 'sysconf directory' : sysconfdir,
2685 'include directory' : includedir,
2686 'lib directory' : libdir,
2687 'SysV init scripts' : sysvinit_path,
2688 'SysV rc?.d directories' : sysvrcnd_path,
2689 'PAM modules directory' : pamlibdir,
2690 'PAM configuration directory' : pamconfdir,
2691 'ssh configuration directory' : sshdconfdir,
2692 'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
2693 'RPM macros directory' : rpmmacrosdir,
2694 'modprobe.d directory' : modprobedir,
2695 'D-Bus policy directory' : dbuspolicydir,
2696 'D-Bus session directory' : dbussessionservicedir,
2697 'D-Bus system directory' : dbussystemservicedir,
2698 'D-Bus interfaces directory' : dbus_interfaces_dir,
2699 'bash completions directory' : bashcompletiondir,
2700 'zsh completions directory' : zshcompletiondir,
2701 'private shared lib version tag' : shared_lib_tag,
2702 'extra start script' : get_option('rc-local'),
2703 'debug shell' : '@0@ @ @1@'.format(get_option('debug-shell'),
2704 get_option('debug-tty')),
2705 'system UIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'),
2706 conf.get('SYSTEM_ALLOC_UID_MIN')),
2707 'system GIDs' : '<=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'),
2708 conf.get('SYSTEM_ALLOC_GID_MIN')),
2709 'dynamic UIDs' : '@0@…@1@'.format(dynamic_uid_min, dynamic_uid_max),
2710 'container UID bases' : '@0@…@1@'.format(container_uid_base_min, container_uid_base_max),
2711 'static UID/GID allocations' : ' '.join(static_ugids),
2712 '/dev/kvm access mode' : get_option('dev-kvm-mode'),
2713 'render group access mode' : get_option('group-render-mode'),
2714 'certificate root directory' : get_option('certificate-root'),
2715 'support URL' : support_url,
2716 'nobody user name' : nobody_user,
2717 'nobody group name' : nobody_group,
2718 'fallback hostname' : get_option('fallback-hostname'),
2719 'default compression method' : compression,
2720 'default DNSSEC mode' : default_dnssec,
2721 'default DNS-over-TLS mode' : default_dns_over_tls,
2722 'default mDNS mode' : default_mdns,
2723 'default LLMNR mode' : default_llmnr,
2724 'default DNS servers' : dns_servers.split(' '),
2725 'default NTP servers' : ntp_servers.split(' '),
2726 'default cgroup hierarchy' : default_hierarchy,
2727 'default net.naming-scheme value' : default_net_naming_scheme,
2728 'default KillUserProcesses value' : kill_user_processes,
2729 'default locale' : default_locale,
2730 'default nspawn locale' : nspawn_locale,
2731 'default status unit format' : status_unit_format_default,
2732 'default user $PATH' :
2733 default_user_path != '' ? default_user_path : '(same as system services)',
2734 'systemd service watchdog' : service_watchdog == '' ? 'disabled' : service_watchdog,
2735 'time epoch' : '@0@ (@1@)'.format(time_epoch, alt_time_epoch)})
2736
2737 # TODO:
2738 # CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
2739 # CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
2740 # LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
2741
2742 found = []
2743 missing = []
2744
2745 foreach tuple : [
2746 # dependencies
2747 ['ACL'],
2748 ['AUDIT'],
2749 ['AppArmor'],
2750 ['IMA'],
2751 ['PAM'],
2752 ['SECCOMP'],
2753 ['SELinux'],
2754 ['SMACK'],
2755 ['blkid'],
2756 ['elfutils'],
2757 ['gcrypt'],
2758 ['gnutls'],
2759 ['libbpf'],
2760 ['libcryptsetup'],
2761 ['libcryptsetup-plugins'],
2762 ['libcurl'],
2763 ['libfdisk'],
2764 ['libfido2'],
2765 ['libidn'],
2766 ['libidn2'],
2767 ['libiptc'],
2768 ['microhttpd'],
2769 ['openssl'],
2770 ['p11kit'],
2771 ['passwdqc'],
2772 ['pcre2'],
2773 ['pwquality'],
2774 ['qrencode'],
2775 ['tpm2'],
2776 ['xkbcommon'],
2777
2778 # compression libs
2779 ['zstd'],
2780 ['lz4'],
2781 ['xz'],
2782 ['zlib'],
2783 ['bzip2'],
2784
2785 # components
2786 ['backlight'],
2787 ['binfmt'],
2788 ['bootloader'],
2789 ['bpf-framework', conf.get('BPF_FRAMEWORK') == 1],
2790 ['coredump'],
2791 ['efi'],
2792 ['environment.d'],
2793 ['firstboot'],
2794 ['hibernate'],
2795 ['homed'],
2796 ['hostnamed'],
2797 ['hwdb'],
2798 ['importd'],
2799 ['initrd'],
2800 ['kernel-install'],
2801 ['localed'],
2802 ['logind'],
2803 ['machined'],
2804 ['networkd'],
2805 ['nss-myhostname'],
2806 ['nss-mymachines'],
2807 ['nss-resolve'],
2808 ['nss-systemd'],
2809 ['oomd'],
2810 ['portabled'],
2811 ['pstore'],
2812 ['quotacheck'],
2813 ['randomseed'],
2814 ['repart'],
2815 ['resolve'],
2816 ['rfkill'],
2817 ['sysext'],
2818 ['systemd-analyze', conf.get('ENABLE_ANALYZE') == 1],
2819 ['sysupdate'],
2820 ['sysusers'],
2821 ['storagetm'],
2822 ['timedated'],
2823 ['timesyncd'],
2824 ['tmpfiles'],
2825 ['userdb'],
2826 ['vconsole'],
2827 ['vmspawn'],
2828 ['xdg-autostart'],
2829
2830 # optional features
2831 ['dmi'],
2832 ['idn'],
2833 ['polkit'],
2834 ['nscd'],
2835 ['legacy-pkla', install_polkit_pkla],
2836 ['kmod'],
2837 ['xenctrl'],
2838 ['dbus'],
2839 ['glib'],
2840 ['tpm'],
2841 ['man pages', want_man],
2842 ['html pages', want_html],
2843 ['man page indices', want_man and have_lxml],
2844 ['SysV compat'],
2845 ['compat-mutable-uid-boundaries'],
2846 ['utmp'],
2847 ['ldconfig'],
2848 ['adm group', get_option('adm-group')],
2849 ['wheel group', get_option('wheel-group')],
2850 ['gshadow'],
2851 ['debug hashmap'],
2852 ['debug mmap cache'],
2853 ['debug siphash'],
2854 ['trace logging', conf.get('LOG_TRACE') == 1],
2855 ['slow tests', slow_tests],
2856 ['fuzz tests', fuzz_tests],
2857 ['install tests', install_tests],
2858 ['link-udev-shared', get_option('link-udev-shared')],
2859 ['link-systemctl-shared', get_option('link-systemctl-shared')],
2860 ['link-networkd-shared', get_option('link-networkd-shared')],
2861 ['link-timesyncd-shared', get_option('link-timesyncd-shared')],
2862 ['link-journalctl-shared', get_option('link-journalctl-shared')],
2863 ['link-boot-shared', get_option('link-boot-shared')],
2864 ['link-portabled-shared', get_option('link-portabled-shared')],
2865 ['first-boot-full-preset'],
2866 ['fexecve'],
2867 ['standalone-binaries', get_option('standalone-binaries')],
2868 ['coverage', get_option('b_coverage')],
2869 ]
2870
2871 if tuple.length() >= 2
2872 cond = tuple[1]
2873 else
2874 ident1 = 'HAVE_' + tuple[0].underscorify().to_upper()
2875 ident2 = 'ENABLE_' + tuple[0].underscorify().to_upper()
2876 cond = conf.get(ident1, 0) == 1 or conf.get(ident2, 0) == 1
2877 endif
2878 if cond
2879 found += tuple[0]
2880 else
2881 missing += tuple[0]
2882 endif
2883 endforeach
2884
2885 if static_libsystemd == 'false'
2886 missing += 'static-libsystemd'
2887 else
2888 found += 'static-libsystemd(@0@)'.format(static_libsystemd)
2889 endif
2890
2891 if static_libudev == 'false'
2892 missing += 'static-libudev'
2893 else
2894 found += 'static-libudev(@0@)'.format(static_libudev)
2895 endif
2896
2897 if conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and conf.get('PREFER_OPENSSL') == 1
2898 found += 'cryptolib(openssl)'
2899 elif conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1
2900 found += 'cryptolib(gcrypt)'
2901 else
2902 missing += 'cryptolib'
2903 endif
2904
2905 if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
2906 found += 'DNS-over-TLS(gnutls)'
2907 elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
2908 found += 'DNS-over-TLS(openssl)'
2909 else
2910 missing += 'DNS-over-TLS'
2911 endif
2912
2913 summary({
2914 'enabled' : ', '.join(found),
2915 'disabled' : ', '.join(missing)},
2916 section : 'Features')