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