From 25714364a981e8e0ca3ac44ff09819a22a46b442 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 28 Jun 2026 21:40:07 +0900 Subject: [PATCH] locale-util: drop libintl dependency Both glibc and musl provides dgettext(). Hence it is not necessary to use libintl.so provided by gettext. This partially reverts 590e22643722cf1268bd24f9056c7115ab0c1cf2, fully reverts commit e6e65dc26157207a6b720fccc49632ac77236384 and bd19ffd9cb618b15cbd74110aeca2abab745fe9e. Then, introduce minimal libintl.h for musl build, to avoid using libintl.h by gettext, which is typically installed on musl-based build systems. --- meson.build | 7 ------- src/basic/locale-util.c | 27 --------------------------- src/basic/locale-util.h | 30 +----------------------------- src/home/pam_systemd_home.c | 10 ---------- src/include/musl/libintl.h | 7 +++++++ src/test/test-dlopen-so.c | 2 -- 6 files changed, 8 insertions(+), 75 deletions(-) create mode 100644 src/include/musl/libintl.h diff --git a/meson.build b/meson.build index 93df01181b..20eba736d7 100644 --- a/meson.build +++ b/meson.build @@ -1011,13 +1011,6 @@ endif libm = cc.find_library('m') -# Header presence check only — dgettext itself is resolved via dlopen_libintl() at runtime, so we never -# link against libintl. On glibc dgettext lives in libc; on musl gettext-dev provides libintl.h alongside -# libintl.so.8 which we dlopen() if present. -if not cc.has_header('libintl.h') - error('libintl.h not found (install gettext / gettext-dev)') -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/basic/locale-util.c b/src/basic/locale-util.c index 1f0692e5bd..9dc74ef36f 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -7,12 +7,7 @@ #include #include -#ifndef __GLIBC__ -#include "sd-dlopen.h" -#endif - #include "dirent-util.h" -#include "dlfcn-util.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" @@ -27,28 +22,6 @@ #include "strv.h" #include "utf8.h" -#ifdef __GLIBC__ -DLSYM_PROTOTYPE(dgettext) = dgettext; -#else -DLSYM_PROTOTYPE(dgettext) = NULL; -#endif - -int dlopen_libintl(int log_level) { -#ifdef __GLIBC__ - return 1; -#else - static void *libintl_dl = NULL; - - LIBINTL_NOTE(SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED); - - return dlopen_many_sym_or_warn( - &libintl_dl, - "libintl.so.8", - log_level, - DLSYM_ARG(dgettext)); -#endif -} - static char* normalize_locale(const char *name) { const char *e; diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index c2cbf3580a..869a0eb4fb 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -4,33 +4,7 @@ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ -#include "sd-dlopen.h" /* IWYU pragma: export */ - #include "basic-forward.h" -#include "dlfcn-util.h" - -/* format_arg(2) propagates the format-string nature of the second argument to the return value, so that - * printf(_("Hello %s"), name) still gets checked. It survives both DLSYM_PROTOTYPE's typeof() and the - * ternary in _() below — verified on gcc and clang. */ -extern DLSYM_PROTOTYPE(dgettext) __attribute__((format_arg(2))); - -int dlopen_libintl(int log_level); - -#ifdef __GLIBC__ -#define DLOPEN_LIBINTL(log_level, priority) dlopen_libintl(log_level) -#else -#define LIBINTL_NOTE(priority) \ - SD_ELF_NOTE_DLOPEN("intl", \ - "Support for message translation via gettext", \ - priority, \ - "libintl.so.8") - -#define DLOPEN_LIBINTL(log_level, priority) \ - ({ \ - LIBINTL_NOTE(priority); \ - dlopen_libintl(log_level); \ - }) -#endif typedef enum LocaleVariable { /* We don't list LC_ALL here on purpose. People should be @@ -58,9 +32,7 @@ int get_locales(char ***ret); bool locale_is_valid(const char *name); int locale_is_installed(const char *name); -/* Falls back to the untranslated string if dlopen_libintl() hasn't run or has failed, so callers don't have - * to gate every translatable message on a runtime check. */ -#define _(String) (sym_dgettext ? sym_dgettext(GETTEXT_PACKAGE, (String)) : (String)) +#define _(String) dgettext(GETTEXT_PACKAGE, String) #define N_(String) String bool is_locale_utf8(void); diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index abb75b9d92..bbfee76f07 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -790,8 +790,6 @@ _public_ PAM_EXTERN int pam_sm_authenticate( if (r < 0) return PAM_SERVICE_ERR; - (void) DLOPEN_LIBINTL(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); /* best-effort: messages won't be translated if this fails */ - pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -857,8 +855,6 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r < 0) return PAM_SERVICE_ERR; - (void) DLOPEN_LIBINTL(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); /* best-effort: messages won't be translated if this fails */ - pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -916,8 +912,6 @@ _public_ PAM_EXTERN int pam_sm_close_session( if (r < 0) return PAM_SERVICE_ERR; - (void) DLOPEN_LIBINTL(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); /* best-effort: messages won't be translated if this fails */ - pam_log_setup(); if (parse_argv(pamh, @@ -983,8 +977,6 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( if (r < 0) return PAM_SERVICE_ERR; - (void) DLOPEN_LIBINTL(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); /* best-effort: messages won't be translated if this fails */ - pam_log_setup(); if (parse_env(pamh, &flags) < 0) @@ -1104,8 +1096,6 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( if (r < 0) return PAM_SERVICE_ERR; - (void) DLOPEN_LIBINTL(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); /* best-effort: messages won't be translated if this fails */ - pam_log_setup(); if (parse_argv(pamh, diff --git a/src/include/musl/libintl.h b/src/include/musl/libintl.h new file mode 100644 index 0000000000..b43dd121aa --- /dev/null +++ b/src/include/musl/libintl.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* On musl-based systems, libintl.h may be provided by GNU gettext even though musl itself provides + * dgettext(). Declare dgettext() directly to avoid an unnecessary dependency on libintl.so. */ + +char* dgettext(const char *domainname, const char *msgid) __attribute__((format_arg(2))); diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index de1d767139..0eca1356c0 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -18,7 +18,6 @@ #include "libcrypt-util.h" #include "libfido2-util.h" #include "libmount-util.h" -#include "locale-util.h" #include "main-func.h" #include "microhttpd-util.h" #include "module-util.h" @@ -66,7 +65,6 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID); ASSERT_DLOPEN(dlopen_libcrypt, HAVE_LIBCRYPT); ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2); - ASSERT_OK(dlopen_libintl(LOG_DEBUG)); /* Required to be available at build time. */ ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD); ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT); ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM);