Android NDK r16 MB_CUR_MAX doesn’t link when compiling C.
Problem found in GNU Emacs, which worked around it this way:
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=39a7e6b79fdeafc539a36f6831d922a2622cb679
... but this ran afoul of the recent Gnulib change that
added lib/stdlib.c.
* lib/stdlib.in.h (gl_MB_CUR_MAX): If @REPLACE_MB_CUR_MAX@
is positive, use its value directly.
* m4/stdlib_h.m4 (gl_STDLIB_H): Set REPLACE_MB_CUR_MAX to (-1)
if the Solaris bug, and to 4 if the Android bug.  Use AS_CASE
so that Emacs can navigate this code better.
* tests/test-stdlib.c (main): Check that MB_CUR_MAX compiles
and is nonzero.
---
 ChangeLog                     | 14 ++++++++++++++
 doc/posix-headers/stdlib.texi |  3 +++
 lib/stdlib.in.h               |  7 ++++++-
 m4/stdlib_h.m4                | 36 ++++++++++++++++++++---------------
 tests/test-stdlib.c           |  3 +++
 5 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 90a80123a2..416a05dd1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2024-12-23  Paul Eggert  <egg...@cs.ucla.edu>
 
+       stdlib: fix MB_CUR_MAX on older Android
+       Android NDK r16 MB_CUR_MAX doesn’t link when compiling C.
+       Problem found in GNU Emacs, which worked around it this way:
+       
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=39a7e6b79fdeafc539a36f6831d922a2622cb679
+       ... but this ran afoul of the recent Gnulib change that
+       added lib/stdlib.c.
+       * lib/stdlib.in.h (gl_MB_CUR_MAX): If @REPLACE_MB_CUR_MAX@
+       is positive, use its value directly.
+       * m4/stdlib_h.m4 (gl_STDLIB_H): Set REPLACE_MB_CUR_MAX to (-1)
+       if the Solaris bug, and to 4 if the Android bug.  Use AS_CASE
+       so that Emacs can navigate this code better.
+       * tests/test-stdlib.c (main): Check that MB_CUR_MAX compiles
+       and is nonzero.
+
        stdlib: MB_CUR_MAX is type size_t
        * lib/stdlib.in.h (gl_MB_CUR_MAX): Return size_t, not int,
        to conform to POSIX.
diff --git a/doc/posix-headers/stdlib.texi b/doc/posix-headers/stdlib.texi
index 3bd2d8e622..0763a20e0b 100644
--- a/doc/posix-headers/stdlib.texi
+++ b/doc/posix-headers/stdlib.texi
@@ -17,6 +17,9 @@ Some platforms provide a @code{NULL} macro that cannot be 
used in arbitrary
 expressions:
 NetBSD 5.0
 @item
+Using the macro @code{MB_CUR_MAX} causes link errors on some platforms:
+Android NDK r16.
+@item
 The value of @code{MB_CUR_MAX} is too small (3 instead of 4) in UTF-8 locales
 on some platforms:
 Solaris 10.
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 43430dfe68..14f45cc21e 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -746,15 +746,20 @@ _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant 
everywhere - "
 # endif
 #endif
 
-/* Return maximum number of bytes of a multibyte character.  */
+/* Return maximum number of bytes in a multibyte character in the
+   current locale.  */
 #if @REPLACE_MB_CUR_MAX@
 # if !GNULIB_defined_MB_CUR_MAX
 _GL_STDLIB_INLINE size_t
 gl_MB_CUR_MAX (void)
 {
+#  if 0 < @REPLACE_MB_CUR_MAX@
+  return @REPLACE_MB_CUR_MAX@;
+#  else
   /* Turn the value 3 to the value 4, as needed for the UTF-8 encoding.  */
   int gl_mb_cur_max = MB_CUR_MAX;
   return gl_mb_cur_max == 3 ? 4 : gl_mb_cur_max;
+#  endif
 }
 #  undef MB_CUR_MAX
 #  define MB_CUR_MAX gl_MB_CUR_MAX ()
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index 87b63ff54e..f1192e3d25 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,5 +1,5 @@
 # stdlib_h.m4
-# serial 82
+# serial 83
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -41,17 +41,17 @@ AC_DEFUN_ONCE([gl_STDLIB_H],
   AC_REQUIRE([gt_LOCALE_EN_UTF8])
   AC_CACHE_CHECK([whether MB_CUR_MAX is correct],
     [gl_cv_macro_MB_CUR_MAX_good],
-    [
-      dnl Initial guess, used when cross-compiling or when no suitable locale
+    [AC_LINK_IFELSE(
+     [AC_LANG_PROGRAM([[#include <stdlib.h>
+                      ]],
+                      [[return !!MB_CUR_MAX;]])],
+     [dnl Initial guess, used when cross-compiling or when no suitable locale
       dnl is present.
-changequote(,)dnl
-      case "$host_os" in
-                           # Guess no on Solaris and Haiku.
-        solaris* | haiku*) gl_cv_macro_MB_CUR_MAX_good="guessing no" ;;
-                           # Guess yes otherwise.
-        *)                 gl_cv_macro_MB_CUR_MAX_good="guessing yes" ;;
-      esac
-changequote([,])dnl
+      # Guess no on Solaris and Haiku, yes otherwise.
+      AS_CASE([$host_os],
+        [solaris* | haiku*],
+          [gl_cv_macro_MB_CUR_MAX_good="guessing no"],
+          [gl_cv_macro_MB_CUR_MAX_good="guessing yes"])
       if test "$LOCALE_EN_UTF8" != none; then
         AC_RUN_IFELSE(
           [AC_LANG_SOURCE([[
@@ -71,11 +71,17 @@ int main ()
           [gl_cv_macro_MB_CUR_MAX_good=no],
           [:])
       fi
+     ],
+     [gl_cv_macro_MB_CUR_MAX_good="link failed - so no"])
     ])
-  case "$gl_cv_macro_MB_CUR_MAX_good" in
-    *yes) ;;
-    *) REPLACE_MB_CUR_MAX=1 ;;
-  esac
+  AS_CASE([$gl_cv_macro_MB_CUR_MAX_good],
+    [*yes],
+      [],
+    ["link failed - so no"],
+      [# 4 suffices as a workaround in Android NDK 16,
+       # the only known platform with the bug.
+       REPLACE_MB_CUR_MAX=4],
+      [REPLACE_MB_CUR_MAX="(-1)"])
 
   AC_CHECK_DECLS_ONCE([ecvt])
   if test $ac_cv_have_decl_ecvt = no; then
diff --git a/tests/test-stdlib.c b/tests/test-stdlib.c
index cb6db8028f..7b9cd50a79 100644
--- a/tests/test-stdlib.c
+++ b/tests/test-stdlib.c
@@ -56,6 +56,9 @@ main (void)
     return 1;
 #endif
 
+  if (MB_CUR_MAX == 0)
+    return 1;
+
   if (test_sys_wait_macros ())
     return 2;
 
-- 
2.45.2


Reply via email to