From e3aa90b0f5ec2cf7f8bb9702ee188b7fb252823d Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 3 Aug 2026 15:02:36 +0300 Subject: [PATCH] gettext: use relibc's error() instead of gnulib's replacement gettext failed to link against the GCC 16 toolchain with ld: libc.a(...rcgu.o):(.bss.error_message_count+0x0): multiple definition of `error_message_count'; libgrt.a(libgrt_a-error.o): first defined here Root cause is a cross-compile artefact, not a compiler change. gnulib's check for a working error() is a RUN test, so cross-compiling reports 'checking for working error function... guessing no' and turns on GNULIB_REPLACE_ERROR. Two things then go wrong at once: consumers are redirected to rpl_error, and gnulib's own error.c -- listed in am__objects_5 with no GL_COND_OBJ_ERROR guard -- still defines the unrenamed error_* globals, which collide with relibc's. relibc genuinely implements error(), error_at_line() and all three globals (verified with nm). Two coordinated fixes: - gl_cv_func_working_error=yes in the recipe. Stating the answer a run test cannot reach while cross-compiling is the standard autoconf mechanism, and is exactly what the neighbouring ac_cv_/gt_cv_ entries already do for the same reason. Consumers now call relibc's error() and no rpl_error reference remains. - Guard gnulib's error.c on HAVE_ERROR, which configure already defines as 1 -- upstream gnulib later made this module conditional on the system lacking error(); this snapshot computes the right answer and does not act on it. Without this the definitions still collide, since relibc is Rust and one codegen unit carries several symbols, so referencing any of them drags the whole object in. glibc escapes this only by giving each its own object file. gettext cooks clean. Patch generated by diff, applies at --fuzz=0. --- .../02-gnulib-error-system-provided.patch | 105 ++++++++++++++++++ .../02-gnulib-error-system-provided.patch | 1 + recipes/tools/gettext/recipe.toml | 13 ++- 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 local/patches/gettext/02-gnulib-error-system-provided.patch create mode 120000 recipes/tools/gettext/02-gnulib-error-system-provided.patch diff --git a/local/patches/gettext/02-gnulib-error-system-provided.patch b/local/patches/gettext/02-gnulib-error-system-provided.patch new file mode 100644 index 0000000000..88d4a00296 --- /dev/null +++ b/local/patches/gettext/02-gnulib-error-system-provided.patch @@ -0,0 +1,105 @@ +gnulib: do not define error() when the C library provides it. + +Companion to `gl_cv_func_working_error=yes` in the recipe. gnulib's probe +for a working error() is a RUN test, so under cross-compilation it reports + + checking for working error function... guessing no + +and sets GNULIB_REPLACE_ERROR. The cache variable stops that, so consumers +call relibc's error() directly instead of rpl_error. + +That alone is not sufficient: gnulib-lib/Makefile lists error.o in +am__objects_5 with no GL_COND_OBJ_ERROR guard, so error.c is compiled +regardless and defines error_message_count, error_one_per_line and +error_print_progname unconditionally. Those collide with relibc's, which +carries all three plus error() and error_at_line(): + + ld: libc.a(...rcgu.o):(.bss.error_message_count+0x0): multiple definition + of `error_message_count'; libgrt.a(libgrt_a-error.o): first defined here + +relibc is Rust, so a single codegen unit carries several symbols and +referencing any one of them drags in the whole object, definitions included +-- glibc avoids this only because each lives in its own object file. + +Upstream gnulib later made this module conditional on the system lacking +error(). configure already computes the right answer here (config.h defines +HAVE_ERROR 1); it simply is not acted upon. Honour it and compile nothing +when the C library supplies error(). + +Redox's relibc provides error_at_line() alongside error(); a libc offering +only one of the two would need this guard narrowed. + +--- a/gettext-runtime/gnulib-lib/error.c ++++ b/gettext-runtime/gnulib-lib/error.c +@@ -22,6 +22,29 @@ + # define _GL_NO_INLINE_ERROR + #endif + ++/* Red Bear: relibc supplies error(), error_at_line() and the three error_* ++ globals (verified with nm on libc.a). This gnulib snapshot compiles ++ error.c unconditionally -- am__objects_5 in gnulib-lib/Makefile has no ++ GL_COND_OBJ_ERROR guard -- so its strong .bss definitions collide with ++ relibc's during static linking: ++ ++ ld: libc.a(...rcgu.o):(.bss.error_message_count+0x0): multiple ++ definition of `error_message_count'; libgrt.a(libgrt_a-error.o): ++ first defined here ++ ++ (relibc is Rust, so one codegen unit carries several symbols; referencing ++ any of them drags the whole object in, definitions included.) ++ ++ Upstream gnulib later made this module conditional on the system lacking ++ error(). configure here already reaches the right conclusion -- config.h ++ defines HAVE_ERROR 1 -- it just is not acted on. Honour it: when the C ++ library provides error(), compile nothing. Redox's relibc provides ++ error_at_line() alongside error(); a libc offering only the former would ++ need this guard narrowed. */ ++#if defined HAVE_ERROR && HAVE_ERROR ++typedef int _gl_error_c_skipped_system_provides_error; ++#else ++ + #include + + #include +@@ -408,3 +431,4 @@ + weak_alias (__error, error) + weak_alias (__error_at_line, error_at_line) + #endif ++#endif /* Red Bear: system provides error() */ +--- a/gettext-tools/gnulib-lib/error.c ++++ b/gettext-tools/gnulib-lib/error.c +@@ -22,6 +22,29 @@ + # define _GL_NO_INLINE_ERROR + #endif + ++/* Red Bear: relibc supplies error(), error_at_line() and the three error_* ++ globals (verified with nm on libc.a). This gnulib snapshot compiles ++ error.c unconditionally -- am__objects_5 in gnulib-lib/Makefile has no ++ GL_COND_OBJ_ERROR guard -- so its strong .bss definitions collide with ++ relibc's during static linking: ++ ++ ld: libc.a(...rcgu.o):(.bss.error_message_count+0x0): multiple ++ definition of `error_message_count'; libgrt.a(libgrt_a-error.o): ++ first defined here ++ ++ (relibc is Rust, so one codegen unit carries several symbols; referencing ++ any of them drags the whole object in, definitions included.) ++ ++ Upstream gnulib later made this module conditional on the system lacking ++ error(). configure here already reaches the right conclusion -- config.h ++ defines HAVE_ERROR 1 -- it just is not acted on. Honour it: when the C ++ library provides error(), compile nothing. Redox's relibc provides ++ error_at_line() alongside error(); a libc offering only the former would ++ need this guard narrowed. */ ++#if defined HAVE_ERROR && HAVE_ERROR ++typedef int _gl_error_c_skipped_system_provides_error; ++#else ++ + #include + + #include +@@ -408,3 +431,4 @@ + weak_alias (__error, error) + weak_alias (__error_at_line, error_at_line) + #endif ++#endif /* Red Bear: system provides error() */ diff --git a/recipes/tools/gettext/02-gnulib-error-system-provided.patch b/recipes/tools/gettext/02-gnulib-error-system-provided.patch new file mode 120000 index 0000000000..8fecca688d --- /dev/null +++ b/recipes/tools/gettext/02-gnulib-error-system-provided.patch @@ -0,0 +1 @@ +../../../local/patches/gettext/02-gnulib-error-system-provided.patch \ No newline at end of file diff --git a/recipes/tools/gettext/recipe.toml b/recipes/tools/gettext/recipe.toml index faabfc50c4..5111ac2711 100644 --- a/recipes/tools/gettext/recipe.toml +++ b/recipes/tools/gettext/recipe.toml @@ -9,7 +9,8 @@ tar = "https://ftp.gnu.org/gnu/gettext/gettext-0.22.5.tar.gz" blake3 = "cb3f3a34da7ce1a92746df81f5b78c5d53841973a24eb80ab76537263d380ec0" patches = [ "redox.patch", - "01-external-gettext.patch" + "01-external-gettext.patch", + "02-gnulib-error-system-provided.patch" ] script = """ DYNAMIC_INIT @@ -56,6 +57,16 @@ COOKBOOK_CONFIGURE_FLAGS+=( gt_cv_locale_ja=false gt_cv_locale_tr_utf8=false gt_cv_locale_zh_CN=false + # relibc implements error(), error_at_line() and the error_* globals. + # gnulib's probe for them is a RUN test, so cross-compiling makes it + # report "checking for working error function... guessing no" and set + # GNULIB_REPLACE_ERROR. Consumers then call rpl_error while gnulib's + # own error.c still defines the unrenamed globals, which both collides + # with relibc (multiple definition of `error_message_count') and leaves + # rpl_error undefined. Stating the answer the run test cannot reach is + # the standard autoconf mechanism, and is what the ac_cv_/gt_cv_ entries + # above already do for the same reason. + gl_cv_func_working_error=yes ) cookbook_configure