SDL: revise iconv detection:

From 17e62abb6dd719ec2bd997d7b49b4c1eafebba7e Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Wed, 22 Nov 2023 23:29:00 +0300
Subject: [PATCH] revise iconv detection:

- check libiconv with a linkage test with iconv.h included
- check libc iconv with a linkage test with iconv.h included
  and LIBICONV_PLUG defined (in case libiconv header is in
  include path)
- add new configuration option to prefer iconv from libiconv,
  if available, over the libc version, defaults to disabled:
  SDL_LIBICONV for cmake, --enable-libiconv for autotools.
- change FreeBSD specific LIBICONV_PLUG define in SDL_iconv.c
  to configuration result.
---
 CMakeLists.txt             |  32 ++++++++---
 configure                  | 105 +++++++++++++++++++++++++++----------
 configure.ac               |  48 +++++++++++++++--
 include/SDL_config.h.cmake |   5 +-
 include/SDL_config.h.in    |   1 +
 src/stdlib/SDL_iconv.c     |   2 +-
 6 files changed, 152 insertions(+), 41 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb7e27c36917..334f98756a6e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -421,6 +421,7 @@ dep_option(SDL_DIRECTFB_SHARED     "Dynamically load directfb support" ON "SDL_D
 set_option(SDL_DUMMYVIDEO          "Use dummy video driver" ON)
 dep_option(SDL_IBUS                "Enable IBus support" ON ${UNIX_SYS} OFF)
 set_option(SDL_SYSTEM_ICONV        "Use iconv() from system-installed libraries" ON)
+set_option(SDL_LIBICONV            "Prefer iconv() from libiconv, if available, over libc version" OFF)
 set_option(SDL_OPENGL              "Include OpenGL support" ON)
 set_option(SDL_OPENGLES            "Include OpenGL ES support" ON)
 set_option(SDL_PTHREADS            "Use POSIX threads for multi-threading" ${SDL_PTHREADS_ENABLED_BY_DEFAULT})
@@ -1123,16 +1124,31 @@ if(SDL_LIBC)
     endif()
 
     if(SDL_SYSTEM_ICONV)
-      check_library_exists(iconv iconv_open "" HAVE_LIBICONV)
-      if(HAVE_LIBICONV)
-        list(APPEND EXTRA_LIBS iconv)
+      check_c_source_compiles("
+        #define LIBICONV_PLUG 1 /* in case libiconv header is in include path */
+        #include <stddef.h>
+        #include <iconv.h>
+        int main(int argc, char **argv) {
+            return iconv_open(NULL,NULL);
+        }" ICONV_IN_LIBC)
+
+      cmake_push_check_state()
+      list(APPEND CMAKE_REQUIRED_LIBRARIES iconv)
+      check_c_source_compiles("
+        #include <stddef.h>
+        #include <iconv.h>
+        int main(int argc, char **argv) {
+            return iconv_open(NULL,NULL);
+        }" ICONV_IN_LIBICONV)
+      cmake_pop_check_state()
+
+      if(ICONV_IN_LIBC OR ICONV_IN_LIBICONV)
         set(HAVE_ICONV 1)
         set(HAVE_SYSTEM_ICONV TRUE)
-      else()
-        check_library_exists(c iconv_open "" HAVE_BUILTIN_ICONV)
-        if(HAVE_BUILTIN_ICONV)
-          set(HAVE_ICONV 1)
-          set(HAVE_SYSTEM_ICONV TRUE)
+        if(ICONV_IN_LIBICONV AND (SDL_LIBICONV OR (NOT ICONV_IN_LIBC)))
+          set(SDL_USE_LIBICONV 1)
+          set(HAVE_LIBICONV TRUE)
+          list(APPEND EXTRA_LIBS iconv)
         endif()
       endif()
     endif()
diff --git a/configure b/configure
index 304db817a39b..3120c796877c 100755
--- a/configure
+++ b/configure
@@ -845,6 +845,7 @@ enable_assertions
 enable_dependency_tracking
 enable_libc
 enable_system_iconv
+enable_libiconv
 enable_gcc_atomics
 enable_atomic
 enable_audio
@@ -1642,6 +1643,8 @@ Optional Features:
   --enable-libc           Use the system C library [default=yes]
   --enable-system-iconv   Use iconv() from system-installed libraries
                           [default=yes]
+  --enable-libiconv       Prefer iconv() from libiconv, if available, over
+                          libc version [default=no]
   --enable-gcc-atomics    Use gcc builtin atomics [default=yes]
   --enable-atomic         Enable the atomic operations subsystem [default=yes]
   --enable-audio          Enable the audio subsystem [default=yes]
@@ -18828,6 +18831,14 @@ else $as_nop
   enable_system_iconv=yes
 fi
 
+# Check whether --enable-libiconv was given.
+if test ${enable_libiconv+y}
+then :
+  enableval=$enable_libiconv;
+else $as_nop
+  enable_libiconv=no
+fi
+
 
 if test x$enable_libc = xyes; then
 
@@ -20043,53 +20054,92 @@ fi
 
 
     if test x$enable_system_iconv = xyes; then
-        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv_open in -liconv" >&5
-printf %s "checking for iconv_open in -liconv... " >&6; }
-if test ${ac_cv_lib_iconv_iconv_open+y}
-then :
-  printf %s "(cached) " >&6
-else $as_nop
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-liconv  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv in libc" >&5
+printf %s "checking for iconv in libc... " >&6; }
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-char iconv_open ();
+         #define LIBICONV_PLUG 1 /* in case libiconv header is in include path */
+         #include <stddef.h>
+         #include <iconv.h>
+
 int
 main (void)
 {
-return iconv_open ();
+
+         iconv_open(NULL,NULL);
+
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_lib_iconv_iconv_open=yes
+  have_libc_iconv=yes
 else $as_nop
-  ac_cv_lib_iconv_iconv_open=no
+  have_libc_iconv=no
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_iconv_open" >&5
-printf "%s\n" "$ac_cv_lib_iconv_iconv_open" >&6; }
-if test "x$ac_cv_lib_iconv_iconv_open" = xyes
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_libc_iconv" >&5
+printf "%s\n" "$have_libc_iconv" >&6; }
+
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv in libiconv" >&5
+printf %s "checking for iconv in libiconv... " >&6; }
+        save_LIBS="$LIBS"
+        LIBS="$LIBS -liconv"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+         #include <stddef.h>
+         #include <iconv.h>
+
+int
+main (void)
+{
+
+         iconv_open(NULL,NULL);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
 then :
-  LIBS="$LIBS -liconv"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -liconv"
+  have_libiconv=yes
+else $as_nop
+  have_libiconv=no
 fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+        LIBS="$save_LIBS"
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_libiconv" >&5
+printf "%s\n" "$have_libiconv" >&6; }
 
-        ac_fn_c_check_func "$LINENO" "iconv" "ac_cv_func_iconv"
-if test "x$ac_cv_func_iconv" = xyes
-then :
-  printf "%s\n" "#define HAVE_ICONV 1" >>confdefs.h
+        if test x$have_libc_iconv = xyes || test x$have_libiconv = xyes; then
 
-fi
+printf "%s\n" "#define HAVE_ICONV 1" >>confdefs.h
 
+
+           if test x$have_libiconv = xyes; then
+              if test x$have_libc_iconv != xyes; then
+                 use_libiconv=yes
+              elif test x$enable_libiconv = xyes; then
+                 use_libiconv=yes
+              fi
+           fi
+           if test x$use_libiconv = xyes; then
+              { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: -- Using iconv() from libiconv" >&5
+printf "%s\n" "-- Using iconv() from libiconv" >&6; }
+
+printf "%s\n" "#define SDL_USE_LIBICONV 1" >>confdefs.h
+
+              EXTRA_LDFLAGS="$EXTRA_LDFLAGS -liconv"
+           else
+              { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: -- Using iconv() from libc" >&5
+printf "%s\n" "-- Using iconv() from libc" >&6; }
+           fi
+        fi
     fi
 
     ac_fn_c_check_member "$LINENO" "struct sigaction" "sa_sigaction" "ac_cv_member_struct_sigaction_sa_sigaction" "#include <signal.h>
@@ -27629,6 +27679,7 @@ if test "x$ac_cv_header_xinput_h" = xyes
 then :
   have_xinput=yes
 fi
+
         if test x$have_xinput = xyes; then
 
 printf "%s\n" "#define HAVE_XINPUT_H 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index e9ffc654e4cf..bf833cb6aa04 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,10 +319,14 @@ AC_ARG_ENABLE(libc,
 [AS_HELP_STRING([--enable-libc], [Use the system C library [default=yes]])],
               , enable_libc=yes)
 
-dnl See whether we are allowed to use libiconv
+dnl See whether we are allowed to use system iconv
 AC_ARG_ENABLE(system-iconv,
 [AS_HELP_STRING([--enable-system-iconv], [Use iconv() from system-installed libraries [default=yes]])],
               , enable_system_iconv=yes)
+dnl See whether we prefer libiconv over libc
+AC_ARG_ENABLE(libiconv,
+[AS_HELP_STRING([--enable-libiconv], [Prefer iconv() from libiconv, if available, over libc version [default=no]])],
+              , enable_libiconv=no)
 
 if test x$enable_libc = xyes; then
     AC_DEFINE(HAVE_LIBC, 1, [ ])
@@ -355,8 +359,46 @@ dnl Checks for library functions.
     AC_CHECK_FUNCS(acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf trunc truncf fmod fmodf log logf log10 log10f lround lroundf pow powf round roundf scalbn scalbnf sin sinf sqrt sqrtf tan tanf)
 
     if test x$enable_system_iconv = xyes; then
-        AC_CHECK_LIB(iconv, iconv_open, [LIBS="$LIBS -liconv"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -liconv"])
-        AC_CHECK_FUNCS(iconv)
+        AC_MSG_CHECKING(for iconv in libc)
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+         #define LIBICONV_PLUG 1 /* in case libiconv header is in include path */
+         #include <stddef.h>
+         #include <iconv.h>
+        ]],[[
+         iconv_open(NULL,NULL);
+        ]])], [have_libc_iconv=yes],[have_libc_iconv=no])
+        AC_MSG_RESULT($have_libc_iconv)
+
+        AC_MSG_CHECKING(for iconv in libiconv)
+        save_LIBS="$LIBS"
+        LIBS="$LIBS -liconv"
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+         #include <stddef.h>
+         #include <iconv.h>
+        ]],[[
+         iconv_open(NULL,NULL);
+        ]])], [have_libiconv=yes],[have_libiconv=no])
+        LIBS="$save_LIBS"
+        AC_MSG_RESULT($have_libiconv)
+
+        if test x$have_libc_iconv = xyes || test x$have_libiconv = xyes; then
+           AC_DEFINE(HAVE_ICONV,1,[ ])
+
+           if test x$have_libiconv = xyes; then
+              if test x$have_libc_iconv != xyes; then
+                 use_libiconv=yes
+              elif test x$enable_libiconv = xyes; then
+                 use_libiconv=yes
+              fi
+           fi
+           if test x$use_libiconv = xyes; then
+              AC_MSG_RESULT([-- Using iconv() from libiconv])
+              AC_DEFINE(SDL_USE_LIBICONV,1,[ ])
+              EXTRA_LDFLAGS="$EXTRA_LDFLAGS -liconv"
+           else
+              AC_MSG_RESULT([-- Using iconv() from libc])
+           fi
+        fi
     fi
 
     AC_CHECK_MEMBER(struct sigaction.sa_sigaction,[AC_DEFINE([HAVE_SA_SIGACTION], 1, [ ])], ,[#include <signal.h>])
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 2c541ebadd0f..b2335f59c340 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -200,6 +200,7 @@
 #cmakedefine HAVE_GETPAGESIZE 1
 #cmakedefine HAVE_MPROTECT 1
 #cmakedefine HAVE_ICONV 1
+#cmakedefine SDL_USE_LIBICONV 1
 #cmakedefine HAVE_PTHREAD_SETNAME_NP 1
 #cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
 #cmakedefine HAVE_SEM_TIMEDWAIT 1
@@ -240,7 +241,7 @@
 
 #cmakedefine HAVE_LIBUDEV_H 1
 #cmakedefine HAVE_LIBSAMPLERATE_H 1
-#cmakedefine HAVE_LIBDECOR_H  1
+#cmakedefine HAVE_LIBDECOR_H 1
 
 #cmakedefine HAVE_D3D_H @HAVE_D3D_H@
 #cmakedefine HAVE_D3D11_H @HAVE_D3D11_H@
@@ -524,7 +525,7 @@
 #cmakedefine SDL_ARM_NEON_BLITTERS @SDL_ARM_NEON_BLITTERS@
 
 /* Whether SDL_DYNAMIC_API needs dlopen */
-#cmakedefine DYNAPI_NEEDS_DLOPEN  @DYNAPI_NEEDS_DLOPEN@
+#cmakedefine DYNAPI_NEEDS_DLOPEN @DYNAPI_NEEDS_DLOPEN@
 
 /* Enable dynamic libsamplerate support */
 #cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index 38792a10a793..26e80231782d 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -204,6 +204,7 @@
 #undef HAVE_GETPAGESIZE
 #undef HAVE_MPROTECT
 #undef HAVE_ICONV
+#undef SDL_USE_LIBICONV
 #undef HAVE_PTHREAD_SETNAME_NP
 #undef HAVE_PTHREAD_SET_NAME_NP
 #undef HAVE_SEM_TIMEDWAIT
diff --git a/src/stdlib/SDL_iconv.c b/src/stdlib/SDL_iconv.c
index 91e496cf94f9..8ed7c822e470 100644
--- a/src/stdlib/SDL_iconv.c
+++ b/src/stdlib/SDL_iconv.c
@@ -31,7 +31,7 @@
 #include "SDL_endian.h"
 
 #if defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
-#ifdef __FreeBSD__
+#ifndef SDL_USE_LIBICONV
 /* Define LIBICONV_PLUG to use iconv from the base instead of ports and avoid linker errors. */
 #define LIBICONV_PLUG 1
 #endif