meson: automate .standalone variant generation via extended 'install' field

Extend the 'install' keyword for executable definitions to accept four
modes—'yes', 'no', 'both', and 'static'—to elegantly manage the creation
and installation of both shared and statically-linked (.standalone) binaries.

- 'yes' / 'no': Standard behavior (mapped to true/false).
- 'both': Installs both the shared and static variants.
- 'static': Installs the static variant under the original name, while
  suffixing the uninstalled shared variant with '.shared'.

With this change, any arbitrary executable can now have its `.standalone`
variant built on demand simply by invoking `ninja <target>.standalone`.
For example, `varlinkctl` did not previously support a standalone variant,
but it can now be built explicitly via `ninja varlinkctl.standalone`.

These `.standalone` binaries are not built by default unless explicitly
specified as a ninja target or enabled via `-Dstandalone-binaries=true`.
Thus, the default build time should remain unaffected.

This centralisation eliminates a massive amount of boilerplate and duplicated
target declarations across almost all subdirectories (e.g., systemd-repart,
systemd-tmpfiles, systemd-shutdown, and systemd-report tools).
This commit is contained in:
Yu Watanabe
2026-07-10 16:29:53 +09:00
parent 4bda7547f4
commit 1f76654f94
19 changed files with 164 additions and 219 deletions
+108 -23
View File
@@ -2019,11 +2019,21 @@ endif
#####################################################################
# The 'install' field is extended to also control whether the automatically
# added variant, which is statically linked with libsystemd-shared, is installed:
# 'yes' : Mapped to true. The static variant will not be installed.
# 'no' : Mapped to false. The static variant will not be installed either.
# 'both' : Mapped to true. The static variant will also be installed.
# 'static' : Mapped to false, and its target name is suffixed with '.shared'.
# The static variant will be installed instead using the original name
# (without the '.standalone' suffix).
# Currently, test and fuzzer executables only support 'yes' or 'no'.
executable_template = {
'include_directories' : includes,
'link_with' : libshared,
'link_with' : [libshared],
'install_rpath' : pkglibdir,
'install' : true,
'install' : 'yes',
'build_by_default' : true,
}
generator_template = executable_template + {
@@ -2040,7 +2050,7 @@ executable_additional_kwargs = {
test_template = executable_template + {
'build_by_default' : want_tests != 'false',
'install' : install_tests,
'install' : install_tests ? 'yes' : 'no',
'install_dir' : unittestsdir,
}
@@ -2051,7 +2061,7 @@ test_additional_kwargs = {
fuzz_template = executable_template + {
'build_by_default' : want_fuzz_tests,
'install' : false,
'install' : 'no',
}
if want_ossfuzz
@@ -2263,7 +2273,6 @@ foreach dict : executables
is_test = name.startswith('test-')
is_fuzz = name.startswith('fuzz-')
is_standalone = name.endswith('.standalone')
build = true
foreach cond : dict.get('conditions', [])
@@ -2276,20 +2285,22 @@ foreach dict : executables
continue
endif
exe_sources = dict.get('sources', []) + dict.get('export', [])
exe_sources_static = dict.get('sources', [])
foreach bpf_name : dict.get('bpf_programs', [])
if bpf_name in bpf_programs_by_name
exe_sources += bpf_programs_by_name[bpf_name]
exe_sources_static += bpf_programs_by_name[bpf_name]
endif
endforeach
exe_sources = exe_sources_static + dict.get('export', [])
kwargs = {}
foreach key, val : dict
if key in ['name', 'dbus', 'public', 'conditions', 'type', 'suite',
'timeout', 'parallel', 'sources', 'import', 'export',
'include_directories', 'build_by_default', 'install',
'bpf_programs']
'bpf_programs', 'link_args_static']
continue
endif
@@ -2329,30 +2340,54 @@ foreach dict : executables
endforeach
endif
build_by_default = dict.get('build_by_default',
have_standalone_binaries or not is_standalone)
if not is_standalone
install = dict.get('install', true)
name_shared = name
name_static = name + '.standalone'
install = dict.get('install')
build_by_default = dict.get('build_by_default')
if install == 'yes'
install_shared = true
install_static = false
build_by_default_shared = build_by_default
build_by_default_static = false
elif install == 'no'
install_shared = false
install_static = false
build_by_default_shared = build_by_default
build_by_default_static = false
elif install == 'both'
if is_test or is_fuzz
error('Install mode "@0@" is not supported for test or fuzzer target "@1@"'.format(install, name))
endif
install_shared = true
install_static = true
build_by_default_shared = build_by_default
build_by_default_static = build_by_default
elif install == 'static'
if is_test or is_fuzz
error('Install mode "@0@" is not supported for test or fuzzer target "@1@"'.format(install, name))
endif
name_shared = name + '.shared'
name_static = name
install_shared = false
install_static = true
build_by_default_shared = false
build_by_default_static = build_by_default
else
install = have_standalone_binaries
error('Unknown install mode "@0@" for target "@1@"'.format(install, name))
endif
exe = executable(
name,
name_shared,
sources : exe_sources,
kwargs : kwargs,
implicit_include_directories : false,
include_directories : include_directories,
build_by_default: build_by_default,
install: install,
build_by_default: build_by_default_shared,
install: install_shared,
)
executables_by_name += { name : exe }
if not is_standalone
sources += exe_sources
endif
executables_by_name += { name_shared : exe }
sources += exe_sources
if 'export' in dict
exported_by_name += {
@@ -2363,7 +2398,7 @@ foreach dict : executables
}
endif
if build_by_default
if build_by_default_shared
if dict.get('dbus', false)
dbus_programs += exe
endif
@@ -2372,6 +2407,56 @@ foreach dict : executables
endif
endif
if not is_test and not is_fuzz
kwargs_static = kwargs
if 'export' in dict
obj = exported_by_name[name]
kwargs_static += { 'objects' : kwargs_static.get('objects', []) + obj['exported'] }
include_directories += obj['include_directories']
endif
link_with_static = []
foreach obj : kwargs_static.get('link_with', [])
if obj.full_path() == libshared.full_path()
link_with_static += [
libshared_static,
libsystemd_static,
]
elif obj.full_path() == libcore.full_path()
link_with_static += libcore_static
else
link_with_static += obj
endif
endforeach
kwargs_static += {
'link_with' : link_with_static,
'link_args' : dict.get('link_args_static', kwargs_static.get('link_args', [])),
}
exe = executable(
name_static,
sources : exe_sources_static,
kwargs : kwargs_static,
implicit_include_directories : false,
include_directories : include_directories,
build_by_default: build_by_default_static,
install: install_static,
)
executables_by_name += { name_static : exe }
if build_by_default_static
if dict.get('dbus', false) and not build_by_default_shared
dbus_programs += exe
endif
if dict.get('public', false)
public_programs += exe
endif
endif
endif
if is_test
type = dict.get('type', '')
suite = dict.get('suite', '')
+1 -1
View File
@@ -59,7 +59,7 @@ executables += [
libseccomp_cflags,
tpm2_cflags,
],
'install' : conf.get('ENABLE_ANALYZE') == 1,
'install' : conf.get('ENABLE_ANALYZE') == 1 ? 'yes' : 'no',
},
core_test_template + {
'sources' : files('test-verify.c'),
+2 -11
View File
@@ -1,14 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
if get_option('link-boot-shared')
boot_link_with = [libshared]
else
boot_link_with = [
libshared_static,
libsystemd_static,
]
endif
executables += [
libexec_template + {
'name' : 'systemd-bless-boot',
@@ -18,7 +9,7 @@ executables += [
'ENABLE_BOOTLOADER',
],
'sources' : files('bless-boot.c'),
'link_with' : boot_link_with,
'install' : get_option('link-boot-shared') ? 'yes' : 'static',
},
generator_template + {
'name' : 'systemd-bless-boot-generator',
@@ -27,7 +18,7 @@ executables += [
'ENABLE_BOOTLOADER',
],
'sources' : files('bless-boot-generator.c'),
'link_with' : boot_link_with,
'install' : get_option('link-boot-shared') ? 'yes' : 'static',
},
libexec_template + {
'name' : 'systemd-boot-check-no-failures',
+1 -1
View File
@@ -23,11 +23,11 @@ executables += [
'HAVE_BLKID',
],
'sources' : bootctl_sources,
'link_with' : boot_link_with,
'dependencies' : [
libopenssl_cflags,
tpm2_cflags,
],
'install' : get_option('link-boot-shared') ? 'yes' : 'static',
},
test_template + {
'sources' : files(
+14 -23
View File
@@ -200,18 +200,6 @@ libcore = shared_library(
install : true,
install_dir : pkglibdir)
core_libs_static = [
libc_wrapper_static,
libcore_static,
libshared_static,
libbasic_static,
libsystemd_static,
]
core_libs_shared = [
libcore,
libshared,
]
systemd_deps = [
libapparmor_cflags,
libaudit_cflags,
@@ -221,11 +209,6 @@ systemd_deps = [
libselinux_cflags,
]
systemd_link_args = get_option('build-static') ? ['-static'] : []
systemd_libs = get_option('build-static') ? core_libs_static : core_libs_shared
executor_libs = get_option('link-executor-shared') ? core_libs_shared : core_libs_static
if conf.get('SYSTEMD_MULTICALL_BINARY') == 1
systemd_sources += systemd_executor_sources
systemd_deps += [
@@ -242,16 +225,20 @@ executables += [
'dbus' : true,
'public' : true,
'sources' : systemd_sources,
'link_args' : systemd_link_args,
'link_with' : systemd_libs,
'link_args_static' : get_option('build-static') ? ['-static'] : [],
'link_with' : [
libcore,
libshared,
],
'dependencies' : systemd_deps,
'install' : get_option('build-static') ? 'static' : 'yes',
},
fuzz_template + {
'sources' : files('fuzz-unit-file.c'),
'link_with' : [
libcore,
libshared
libshared,
],
'dependencies' : libmount_cflags,
},
@@ -259,14 +246,14 @@ executables += [
'sources' : files('fuzz-manager-serialize.c'),
'link_with' : [
libcore,
libshared
libshared,
],
},
fuzz_template + {
'sources' : files('fuzz-execute-serialize.c'),
'link_with' : [
libcore,
libshared
libshared,
],
},
]
@@ -282,7 +269,10 @@ else
'name' : 'systemd-executor',
'public' : true,
'sources' : systemd_executor_sources,
'link_with' : executor_libs,
'link_with' : [
libcore,
libshared,
],
'dependencies' : [
libapparmor_cflags,
libbpf_cflags,
@@ -293,6 +283,7 @@ else
libseccomp_cflags,
libselinux_cflags,
],
'install' : get_option('link-executor-shared') ? 'yes' : 'static',
},
]
endif
+1 -2
View File
@@ -6,8 +6,7 @@ executables += [
'public' : true,
'conditions' : ['ENABLE_HWDB'],
'sources' : files('hwdb.c'),
'link_with' : udev_link_with,
'install_rpath' : udev_rpath,
'install' : get_option('link-udev-shared') ? 'yes' : 'static',
'install_tag' : 'hwdb',
},
]
+1 -1
View File
@@ -44,7 +44,7 @@ executables += [
# We always build systemd-journal-remote regardless of ENABLE_REMOTE because we have to build
# fuzz-journal-remote even when --auto-features=disabled (see tools/oss-fuzz.sh for why).
# Instead, we make sure we don't install it when the remote feature is disabled.
'install' : conf.get('ENABLE_REMOTE') == 1,
'install' : conf.get('ENABLE_REMOTE') == 1 ? 'yes' : 'no',
'sources' : systemd_journal_remote_sources,
'export' : systemd_journal_remote_export_sources,
'dependencies' : common_deps + [libmicrohttpd_cflags],
+1 -10
View File
@@ -68,15 +68,6 @@ journalctl_sources = files(
'journalctl-varlink-server.c',
)
if get_option('link-journalctl-shared')
journalctl_link_with = [libshared]
else
journalctl_link_with = [
libshared_static,
libsystemd_static,
]
endif
journal_test_template = test_template + {
'import' : ['systemd-journald'],
}
@@ -123,7 +114,6 @@ executables += [
'name' : 'journalctl',
'public' : true,
'sources' : journalctl_sources,
'link_with' : journalctl_link_with,
'dependencies' : [
liblz4_cflags,
libopenssl_cflags,
@@ -131,6 +121,7 @@ executables += [
libxz_cflags,
libzstd_cflags,
],
'install' : get_option('link-journalctl-shared') ? 'yes' : 'static',
},
journal_test_template + {
'sources' : files('test-audit-type.c'),
+8 -14
View File
@@ -163,19 +163,12 @@ netdev_gperf_c = custom_target(
generated_sources += [networkd_gperf_c, networkd_network_gperf_c, netdev_gperf_c]
systemd_networkd_export_sources += [networkd_gperf_c, networkd_network_gperf_c, netdev_gperf_c]
if get_option('link-networkd-shared')
networkd_link_with = [libshared]
else
networkd_link_with = [libsystemd_static,
libshared_static]
endif
network_includes = [include_directories(['.', 'netdev', 'tc']), libsystemd_network_includes]
network_test_template = test_template + {
'conditions' : ['ENABLE_NETWORKD'],
'link_with' : [
networkd_link_with,
libshared,
libsystemd_network,
],
'import' : ['systemd-networkd'],
@@ -185,7 +178,7 @@ network_test_template = test_template + {
network_fuzz_template = fuzz_template + {
'conditions' : ['ENABLE_NETWORKD'],
'link_with' : [
networkd_link_with,
libshared,
libsystemd_network,
],
'import' : ['systemd-networkd'],
@@ -201,8 +194,8 @@ executables += [
'export' : systemd_networkd_export_sources,
'include_directories' : network_includes,
'link_with' : [
libshared,
libsystemd_network,
networkd_link_with,
],
'dependencies' : [
libbpf_cflags,
@@ -210,13 +203,14 @@ executables += [
'bpf_programs': [
'sysctl-monitor',
],
'install' : get_option('link-networkd-shared') ? 'yes' : 'static',
},
libexec_template + {
'name' : 'systemd-networkd-wait-online',
'public' : true,
'conditions' : ['ENABLE_NETWORKD'],
'sources' : systemd_networkd_wait_online_sources,
'link_with' : networkd_link_with,
'install' : get_option('link-networkd-shared') ? 'yes' : 'static',
},
executable_template + {
'name' : 'networkctl',
@@ -225,18 +219,19 @@ executables += [
'sources' : networkctl_sources,
'include_directories' : libsystemd_network_includes,
'link_with' : [
libshared,
libsystemd_network,
networkd_link_with,
],
'dependencies' : [
libselinux_cflags,
],
'install' : get_option('link-networkd-shared') ? 'yes' : 'static',
},
libexec_template + {
'name' : 'systemd-network-generator',
'sources' : files('generator/network-generator-main.c'),
'export' : files('generator/network-generator.c'),
'link_with' : networkd_link_with,
'install' : get_option('link-networkd-shared') ? 'yes' : 'static',
},
test_template + {
'sources' : files('generator/test-network-generator.c'),
@@ -263,7 +258,6 @@ executables += [
test_template + {
'sources' : files('test-modem-manager-mock.c'),
'conditions' : ['ENABLE_NETWORKD'],
'link_with' : [libshared],
'type' : 'manual',
},
network_fuzz_template + {
+2 -11
View File
@@ -13,32 +13,23 @@ systemd_portabled_sources = files(
'portabled.c',
)
if get_option('link-portabled-shared')
portabled_link_with = [libshared]
else
portabled_link_with = [
libshared_static,
libsystemd_static,
]
endif
executables += [
libexec_template + {
'name' : 'systemd-portabled',
'dbus' : true,
'sources' : systemd_portabled_sources,
'link_with' : portabled_link_with,
'dependencies' : [
libcryptsetup_cflags,
libmount_cflags,
libselinux_cflags,
],
'install' : get_option('link-portabled-shared') ? 'yes' : 'static',
},
executable_template + {
'name' : 'portablectl',
'public' : true,
'sources' : files('portablectl.c'),
'link_with' : portabled_link_with,
'install' : get_option('link-portabled-shared') ? 'yes' : 'static',
},
]
+1 -19
View File
@@ -21,25 +21,7 @@ executables += [
libopenssl_cflags,
tpm2_cflags,
],
},
executable_template + {
'name' : 'systemd-repart.standalone',
'public' : true,
'import' : ['systemd-repart'],
'link_with' : [
libc_wrapper_static,
libbasic_static,
libshared_static,
libsystemd_static,
],
'dependencies' : [
libblkid_cflags,
libcryptsetup_cflags,
libfdisk_cflags,
libmount_cflags,
libopenssl_cflags,
tpm2_cflags,
],
'install' : have_standalone_binaries ? 'both' : 'yes',
},
]
+13 -30
View File
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
report_executables = [
{
executables += [
libexec_template + {
'name' : 'systemd-report',
'public' : true,
'export' : files(
@@ -13,64 +13,47 @@ report_executables = [
'dependencies' : [
libcurl_cflags,
],
'install' : have_standalone_binaries ? 'both' : 'yes',
},
{
libexec_template + {
'name' : 'systemd-report-basic',
'public' : true,
'export' : files(
'report-basic.c',
'report-basic-server.c',
),
'install' : have_standalone_binaries ? 'both' : 'yes',
},
{
libexec_template + {
'name' : 'systemd-report-cgroup',
'export' : files(
'report-cgroup.c',
'report-cgroup-server.c',
),
'install' : have_standalone_binaries ? 'both' : 'yes',
},
{
libexec_template + {
'name' : 'systemd-report-files',
'export' : files(
'report-files.c',
'report-files-server.c',
),
'install' : have_standalone_binaries ? 'both' : 'yes',
},
{
libexec_template + {
'name' : 'systemd-report-sign-plain',
'export' : files(
'report-sign-plain.c',
),
'dependencies' : libopenssl_cflags,
'conditions' : ['HAVE_OPENSSL'],
'install' : have_standalone_binaries ? 'both' : 'yes',
},
{
libexec_template + {
'name' : 'systemd-report-sign-tsm',
'export' : files(
'report-sign-tsm.c',
),
'install' : have_standalone_binaries ? 'both' : 'yes',
},
]
foreach exe : report_executables
exe2 = {
'name' : exe['name'] + '.standalone',
'import' : [exe['name']],
'link_with' : [
libc_wrapper_static,
libbasic_static,
libshared_static,
libsystemd_static,
]
}
foreach optional : ['public', 'dependencies', 'conditions']
if optional in exe
exe2 += { optional : exe[optional] }
endif
endforeach
executables += [
libexec_template + exe,
libexec_template + exe2,
]
endforeach
+1 -11
View File
@@ -19,17 +19,7 @@ executables += [
'shutdown.c',
) + shutdown_detach_sources,
'dependencies' : libmount_cflags,
},
libexec_template + {
'name' : 'systemd-shutdown.standalone',
'import' : ['systemd-shutdown'],
'link_with' : [
libc_wrapper_static,
libbasic_static,
libshared_static,
libsystemd_static,
],
'dependencies' : libmount_cflags,
'install' : have_standalone_binaries ? 'both' : 'yes',
},
test_template + {
'sources' : files('test-umount.c') +
+1 -9
View File
@@ -40,31 +40,23 @@ systemctl_export_sources = files(
'systemctl.c',
)
if get_option('link-systemctl-shared')
systemctl_link_with = [libshared]
else
systemctl_link_with = [libsystemd_static,
libshared_static]
endif
executables += [
executable_template + {
'name' : 'systemctl',
'public' : true,
'sources' : systemctl_sources,
'export' : systemctl_export_sources,
'link_with' : systemctl_link_with,
'dependencies' : [
liblz4_cflags,
libxz_cflags,
libzstd_cflags,
],
'install' : get_option('link-systemctl-shared') ? 'yes' : 'static',
'install_tag' : 'systemctl',
},
fuzz_template + {
'sources' : files('fuzz-systemctl-parse-argv.c'),
'import' : ['systemctl'],
'link_with' : systemctl_link_with,
'dependencies' : [
libselinux_cflags,
],
+1 -12
View File
@@ -10,17 +10,6 @@ executables += [
'public' : true,
'export' : files('sysusers.c'),
'dependencies' : libaudit_cflags,
},
executable_template + {
'name' : 'systemd-sysusers.standalone',
'public' : true,
'import' : ['systemd-sysusers'],
'link_with' : [
libc_wrapper_static,
libbasic_static,
libshared_static,
libsystemd_static,
],
'dependencies' : libaudit_cflags,
'install' : have_standalone_binaries ? 'both' : 'yes',
},
]
+4 -3
View File
@@ -17,6 +17,7 @@ test_env = {
'SYSTEMD_SLOW_TESTS' : want_slow_tests ? '1' : '0',
'PYTHONDONTWRITEBYTECODE' : '1',
'SYSTEMD_LIBC' : get_option('libc'),
'SYSTEMD_BUILD_MODE' : get_option('mode'),
}
if conf.get('ENABLE_LOCALED') == 1
test_env += {'SYSTEMD_LANGUAGE_FALLBACK_MAP' : language_fallback_map}
@@ -349,7 +350,7 @@ executables += [
libc_wrapper_static,
libbasic_static,
],
'install' : false,
'install' : 'no',
'type' : 'manual',
},
test_template + {
@@ -721,7 +722,7 @@ if static_libsystemd != 'false'
'sources' : [test_libsystemd_sym_c],
'link_with' : install_libsystemd_static,
'build_by_default' : want_tests != 'false',
'install' : install_tests,
'install' : install_tests ? 'yes' : 'no',
'suite' : 'libsystemd',
},
]
@@ -736,7 +737,7 @@ if static_libudev != 'false'
'c_args' : ['-Wno-deprecated-declarations'] + test_cflags,
'link_with' : install_libudev_static,
'build_by_default' : want_tests != 'false',
'install' : install_tests,
'install' : install_tests ? 'yes' : 'no',
'suite' : 'libudev',
},
]
+1 -8
View File
@@ -22,20 +22,13 @@ timesyncd_gperf_c = custom_target(
generated_sources += timesyncd_gperf_c
timesyncd_export_sources += timesyncd_gperf_c
if get_option('link-timesyncd-shared')
timesyncd_link_with = [libshared]
else
timesyncd_link_with = [libsystemd_static,
libshared_static]
endif
executables += [
libexec_template + {
'name' : 'systemd-timesyncd',
'sources' : timesyncd_sources,
'export' : timesyncd_export_sources,
'link_with' : timesyncd_link_with,
'dependencies' : libm,
'install' : get_option('link-timesyncd-shared') ? 'yes' : 'static',
},
libexec_template + {
'name' : 'systemd-time-wait-sync',
+1 -15
View File
@@ -16,21 +16,7 @@ executables += [
libacl_cflags,
libselinux_cflags,
],
},
executable_template + {
'name' : 'systemd-tmpfiles.standalone',
'public' : true,
'import' : ['systemd-tmpfiles'],
'link_with' : [
libc_wrapper_static,
libbasic_static,
libshared_static,
libsystemd_static,
],
'dependencies' : [
libacl_cflags,
libselinux_cflags,
],
'install' : have_standalone_binaries ? 'both' : 'yes',
},
test_template + {
'sources' : files('test-offline-passwd.c') +
+2 -15
View File
@@ -106,17 +106,6 @@ generated_sources += link_config_gperf_c
############################################################
if get_option('link-udev-shared')
udev_link_with = [libshared]
udev_rpath = pkglibdir
else
udev_link_with = [libshared_static,
libsystemd_static]
udev_rpath = ''
endif
############################################################
udev_dependencies = [
libacl_cflags,
libblkid_cflags,
@@ -128,8 +117,7 @@ udev_dependencies = [
udev_plugin_template = executable_template + {
'public' : true,
'link_with' : udev_link_with,
'install_rpath' : udev_rpath,
'install' : get_option('link-udev-shared') ? 'yes' : 'static',
'install_dir' : udevlibexecdir,
'install_tag' : 'udev',
}
@@ -156,8 +144,7 @@ udev_binaries_dict = [
libexec_template['include_directories'],
],
'dependencies' : udev_dependencies,
'link_with' : udev_link_with,
'install_rpath' : udev_rpath,
'install' : get_option('link-udev-shared') ? 'yes' : 'static',
'install_tag' : 'udev',
},
udev_plugin_template + {