From a4c45279a76235f2cc9c298b6a30e3de668cb00b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 7 Jul 2025 14:11:19 +0900 Subject: [PATCH 1/6] musl: meson: allow to choose libc implementation This also introduces skeleton directories for storing musl specific code. --- meson.build | 14 +++++++++++++- meson_options.txt | 2 ++ src/libc/meson.build | 2 ++ src/libc/musl/meson.build | 5 +++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/libc/musl/meson.build diff --git a/meson.build b/meson.build index f0b921879b..e5fd89e60c 100644 --- a/meson.build +++ b/meson.build @@ -72,7 +72,10 @@ conf.set10('SD_BOOT', false) # Create a title-less summary section early, so it ends up first in the output. # More items are added later after they have been detected. -summary({'build mode' : get_option('mode')}) +summary({ + 'libc' : get_option('libc'), + 'build mode' : get_option('mode'), +}) ##################################################################### @@ -2069,6 +2072,15 @@ system_includes = [ ), ] +if get_option('libc') == 'musl' + system_include_args = [ + '-isystem', meson.project_build_root() / 'src/include/musl', + '-isystem', meson.project_source_root() / 'src/include/musl', + ] + system_include_args + + system_includes += include_directories('src/include/musl', is_system : true) +endif + basic_includes = [ include_directories( 'src/basic', diff --git a/meson_options.txt b/meson_options.txt index 3cc314eacd..1d7c4f4bd2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -402,6 +402,8 @@ option('ima', type : 'boolean', option('ipe', type : 'boolean', description : 'IPE support') +option('libc', type : 'combo', choices : ['glibc', 'musl'], + description : 'libc implementation to be used') option('acl', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libacl support') option('audit', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, diff --git a/src/libc/meson.build b/src/libc/meson.build index eeee98c9d6..306512ffd7 100644 --- a/src/libc/meson.build +++ b/src/libc/meson.build @@ -16,6 +16,8 @@ libc_wrapper_sources = files( 'xattr.c', ) +subdir('musl') + sources += libc_wrapper_sources libc_wrapper_static = static_library( diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build new file mode 100644 index 0000000000..a876230c67 --- /dev/null +++ b/src/libc/musl/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +if get_option('libc') != 'musl' + subdir_done() +endif From bd19ffd9cb618b15cbd74110aeca2abab745fe9e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 6 Sep 2025 16:25:41 +0900 Subject: [PATCH 2/6] musl: meson: explicitly link with libintl when necessary On some musl based distributions dgettext() may be provided by libintl.so. Hence, we need to add dependency in that case. --- meson.build | 16 ++++++++++++++++ src/home/meson.build | 1 + 2 files changed, 17 insertions(+) diff --git a/meson.build b/meson.build index e5fd89e60c..e3ee957fd5 100644 --- a/meson.build +++ b/meson.build @@ -1005,6 +1005,22 @@ librt = cc.find_library('rt') libm = cc.find_library('m') libdl = cc.find_library('dl') +# On some distributions that use musl (e.g. Alpine), libintl.h may be provided by gettext rather than musl. +# In that case, we need to explicitly link with libintl.so. +if cc.has_function('dgettext', + prefix : '''#include ''', + args : '-D_GNU_SOURCE') + libintl = [] +else + libintl = cc.find_library('intl') + if not cc.has_function('dgettext', + prefix : '''#include ''', + args : '-D_GNU_SOURCE', + dependencies : libintl) + error('dgettext() not found') + endif +endif + # On some architectures, libatomic is required. But on some installations, # it is found, but actual linking fails. So let's try to use it opportunistically. # If it is installed, but not needed, it will be dropped because of --as-needed. diff --git a/src/home/meson.build b/src/home/meson.build index ebecc7b9c2..f40f935d55 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -115,6 +115,7 @@ modules += [ 'sources' : pam_systemd_home_sources, 'dependencies' : [ libcrypt, + libintl, libpam_misc, libpam, threads, From fb33d20c072f2e7c3d500f00f8c04c99271f34c1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 10 Jun 2025 00:29:46 +0900 Subject: [PATCH 3/6] musl: meson: explicitly set _LARGEFILE64_SOURCE glibc sets it when _GNU_SOURCE is defined, however, musl does not. Let's explicitly define it to make getdents64() and struct dirent64 available even when building with musl. --- meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/meson.build b/meson.build index e3ee957fd5..6d576b4d20 100644 --- a/meson.build +++ b/meson.build @@ -560,6 +560,10 @@ conf.set10('HAVE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT', have) conf.set('_GNU_SOURCE', 1) conf.set('__SANE_USERSPACE_TYPES__', true) +# glibc always defines _LARGEFILE64_SOURCE when _GNU_SOURCE is set, but musl does not do that, +# and it is necessary for making getdents64() and struct dirent64 exist. +conf.set('_LARGEFILE64_SOURCE', 1) + conf.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include ')) conf.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include ')) conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include ')) From 0736854da9dcfd06972b34aa7566e46e2997ca39 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 9 Jun 2025 13:37:38 +0900 Subject: [PATCH 4/6] musl: meson: make musl not define wchar_t in their header Otherwise, musl defines wchar_t as int, which conflicts with the assumption by sd-boot, i.e. wchar_t is 2 bytes. Fixes the following build error: ``` In file included from ../src/boot/efi-log.h:4, from ../src/boot/linux_x86.c:13: ../src/boot/efi.h:19:24: error: conflicting types for 'wchar_t'; have 'short unsigned int' 19 | typedef __WCHAR_TYPE__ wchar_t; | ^~~~~~~ In file included from /usr/include/stddef.h:19, from ../src/boot/efi.h:9: /usr/include/bits/alltypes.h:10:13: note: previous declaration of 'wchar_t' with type 'wchar_t' {aka 'int'} 10 | typedef int wchar_t; | ^~~~~~~ ``` --- src/boot/meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/boot/meson.build b/src/boot/meson.build index ee86af274e..3d1f66a658 100644 --- a/src/boot/meson.build +++ b/src/boot/meson.build @@ -182,6 +182,11 @@ if get_option('mode') == 'developer' and get_option('debug') efi_c_args += '-DEFI_DEBUG' endif +if get_option('libc') == 'musl' + # To make musl not define wchar_t as int, rather than short. + efi_c_args += '-D__DEFINED_wchar_t' +endif + efi_c_ld_args = [ '-nostdlib', '-static-pie', From 17e343b58b862306454b64cd66a26588420cffd3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 9 Jun 2025 13:00:37 +0900 Subject: [PATCH 5/6] musl: meson: check existence of renameat2() musl-1.2.5 does not provide renameat2(). Note, it is added by https://github.com/kraj/musl/commit/05ce67fea99ca09cd4b6625cff7aec9cc222dd5a, hence hopefully it will be provided by musl-1.2.6 or newer. --- meson.build | 1 + src/include/musl/stdio.h | 13 +++++++++++++ src/libc/musl/meson.build | 4 ++++ src/libc/musl/stdio.c | 11 +++++++++++ 4 files changed, 29 insertions(+) create mode 100644 src/include/musl/stdio.h create mode 100644 src/libc/musl/stdio.c diff --git a/meson.build b/meson.build index 6d576b4d20..a7c7a0a810 100644 --- a/meson.build +++ b/meson.build @@ -579,6 +579,7 @@ assert(long_max > 100000) conf.set_quoted('LONG_MAX_STR', f'@long_max@') foreach ident : [ + ['renameat2', '''#include '''], # since musl-1.2.6 ['set_mempolicy', '''#include '''], # declared at numaif.h provided by libnuma, which we do not use ['get_mempolicy', '''#include '''], # declared at numaif.h provided by libnuma, which we do not use ['strerrorname_np', '''#include '''], # since glibc-2.32 diff --git a/src/include/musl/stdio.h b/src/include/musl/stdio.h new file mode 100644 index 0000000000..d677201f45 --- /dev/null +++ b/src/include/musl/stdio.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +#if !HAVE_RENAMEAT2 +# define RENAME_NOREPLACE (1 << 0) +# define RENAME_EXCHANGE (1 << 1) +# define RENAME_WHITEOUT (1 << 2) + +int missing_renameat2(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags); +# define renameat2 missing_renameat2 +#endif diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index a876230c67..8d06d919ef 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -3,3 +3,7 @@ if get_option('libc') != 'musl' subdir_done() endif + +libc_wrapper_sources += files( + 'stdio.c', +) diff --git a/src/libc/musl/stdio.c b/src/libc/musl/stdio.c new file mode 100644 index 0000000000..102a22cd5c --- /dev/null +++ b/src/libc/musl/stdio.c @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include + +#if !HAVE_RENAMEAT2 +int missing_renameat2(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags) { + return syscall(__NR_renameat2, __oldfd, __old, __newfd, __new, __flags); +} +#endif From 7dad0db2ee5a52d7ef7aca70f4d97ffd70212b12 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 22 Jun 2025 02:16:25 +0900 Subject: [PATCH 6/6] musl: meson: gracefully disable gshadow, nss, and idn support - musl does not support gshadow, and does not provide gshadow.h, - musl does not support nss, and does not provide nss.h which is necessary for each nss modules, - musl does not provide NI_IDN. --- meson.build | 127 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 49 deletions(-) diff --git a/meson.build b/meson.build index a7c7a0a810..599d2a3217 100644 --- a/meson.build +++ b/meson.build @@ -708,6 +708,8 @@ foreach header : [ endforeach foreach header : [ + 'gshadow.h', + 'nss.h', 'sys/sdt.h', 'threads.h', 'valgrind/memcheck.h', @@ -718,6 +720,20 @@ foreach header : [ cc.has_header(header)) endforeach +foreach ident : [ + ['NI_IDN', 'netdb.h'] + ] + + if meson.version().version_compare('>=1.3.0') + have = cc.has_define(ident[0], + prefix : '''#include <@0@>'''.format(ident[1]), + args : '-D_GNU_SOURCE') + else + have = cc.has_header_symbol(ident[1], ident[0]) + endif + conf.set10('HAVE_' + ident[0], have) +endforeach + ##################################################################### fallback_hostname = get_option('fallback-hostname') @@ -1627,52 +1643,60 @@ conf.set10('ENABLE_NSPAWN', feature.allowed()) conf.set10('DEFAULT_MOUNTFSD_TRUSTED_DIRECTORIES', get_option('default-mountfsd-trusted-directories')) -foreach term : ['analyze', - 'backlight', - 'binfmt', - 'compat-mutable-uid-boundaries', - 'coredump', - 'efi', - 'environment-d', - 'firstboot', - 'gshadow', - 'hibernate', - 'hostnamed', - 'hwdb', - 'idn', - 'ima', - 'ipe', - 'initrd', - 'kernel-install', - 'ldconfig', - 'localed', - 'logind', - 'machined', - 'mountfsd', - 'networkd', - 'nsresourced', - 'nss-myhostname', - 'nss-systemd', - 'oomd', - 'portabled', - 'pstore', - 'quotacheck', - 'randomseed', - 'resolve', - 'rfkill', - 'smack', - 'sysext', - 'sysusers', - 'timedated', - 'timesyncd', - 'tmpfiles', - 'tpm', - 'userdb', - 'utmp', - 'vconsole', - 'xdg-autostart'] - have = get_option(term) - name = 'ENABLE_' + term.underscorify().to_upper() +foreach tuple : [ + ['analyze'], + ['backlight'], + ['binfmt'], + ['compat-mutable-uid-boundaries'], + ['coredump'], + ['efi'], + ['environment-d'], + ['firstboot'], + ['gshadow', conf.get('HAVE_GSHADOW_H') == 1, 'gshadow.h not found'], + ['hibernate'], + ['hostnamed'], + ['hwdb'], + ['idn', conf.get('HAVE_NI_IDN') == 1, 'NI_IDN is not defined'], + ['ima'], + ['ipe'], + ['initrd'], + ['kernel-install'], + ['ldconfig'], + ['localed'], + ['logind'], + ['machined'], + ['mountfsd'], + ['networkd'], + ['nsresourced'], + ['nss-myhostname', conf.get('HAVE_NSS_H') == 1, 'nss.h not found'], + ['nss-systemd', conf.get('HAVE_NSS_H') == 1, 'nss.h not found'], + ['oomd'], + ['portabled'], + ['pstore'], + ['quotacheck'], + ['randomseed'], + ['resolve'], + ['rfkill'], + ['smack'], + ['sysext'], + ['sysusers'], + ['timedated'], + ['timesyncd'], + ['tmpfiles'], + ['tpm'], + ['utmp'], + ['userdb'], + ['vconsole'], + ['xdg-autostart'], + ] + + have = get_option(tuple[0]) + if have and tuple.length() >= 3 and not tuple[1] + warning('@0@ support is requested but @1@, disabling it'.format(tuple[0], tuple[2])) + have = false + endif + + name = 'ENABLE_' + tuple[0].underscorify().to_upper() conf.set10(name, have) endforeach @@ -1681,11 +1705,16 @@ enable_sysusers = conf.get('ENABLE_SYSUSERS') == 1 foreach tuple : [['nss-mymachines', 'machined'], ['nss-resolve', 'resolve']] want = get_option(tuple[0]) - if want.allowed() - have = get_option(tuple[1]) - if want.enabled() and not have + if want.enabled() + if conf.get('HAVE_NSS_H') != 1 + error('@0@ is requested but nss.h not found'.format(tuple[0])) + endif + if not get_option(tuple[1]) error('@0@ is requested but @1@ is disabled'.format(tuple[0], tuple[1])) endif + have = true + elif want.allowed() + have = get_option(tuple[1]) and conf.get('HAVE_NSS_H') == 1 else have = false endif