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