[Python-checkins] bpo-45747: Detect gdbm/dbm dependencies in configure (GH-29467)

tiran webhook-mailer at python.org
Wed Nov 10 14:27:05 EST 2021


https://github.com/python/cpython/commit/0a9f69539be27acf1cddf1b58d02a88d02e5008d
commit: 0a9f69539be27acf1cddf1b58d02a88d02e5008d
branch: main
author: Christian Heimes <christian at python.org>
committer: tiran <christian at python.org>
date: 2021-11-10T20:26:55+01:00
summary:

bpo-45747: Detect gdbm/dbm dependencies in configure (GH-29467)

Co-authored-by: Erlend Egeberg Aasland <erlend.aasland at innova.no>

files:
A Misc/NEWS.d/next/Build/2021-11-08-11-31-48.bpo-45747.AODmk_.rst
M Doc/whatsnew/3.11.rst
M Modules/Setup
M Modules/_dbmmodule.c
M configure
M configure.ac
M pyconfig.h.in
M setup.py

diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 27062f6162ac8..c0a6ce4c35ad8 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -528,6 +528,10 @@ Build Changes
   detected by :program:`configure`.
   (Contributed by Christian Heimes in :issue:`45763`.)
 
+* Build dependencies for :mod:`dbm` are now detected by :program:`configure`.
+  ``libdb`` 3.x and 4.x are no longer supported.
+  (Contributed by Christian Heimes in :issue:`45747`.)
+
 C API Changes
 =============
 
diff --git a/Misc/NEWS.d/next/Build/2021-11-08-11-31-48.bpo-45747.AODmk_.rst b/Misc/NEWS.d/next/Build/2021-11-08-11-31-48.bpo-45747.AODmk_.rst
new file mode 100644
index 0000000000000..f60b83fd5aff1
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2021-11-08-11-31-48.bpo-45747.AODmk_.rst
@@ -0,0 +1 @@
+gdbm and dbm build dependencies are now detected by ``configure``.
diff --git a/Modules/Setup b/Modules/Setup
index 57584f38fd8e7..49c6903121616 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -216,7 +216,7 @@ time timemodule.c
 #_bz2 _bz2module.c -lbz2
 #_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/stgdict.c _ctypes/cfield.c -ldl -lffi -DHAVE_FFI_PREP_CIF_VAR -DHAVE_FFI_PREP_CLOSURE_LOC -DHAVE_FFI_CLOSURE_ALLOC
 # The _dbm module supports NDBM, GDBM with compat module, and Berkeley DB.
-#_dbm _dbmmodule.c -lgdbm_compat -DHAVE_NDBM_H
+#_dbm _dbmmodule.c -lgdbm_compat -DUSE_GDBM_COMPAT
 #_gdbm _gdbmmodule.c -lgdbm
 #_lzma _lzmamodule.c -llzma
 #_sqlite3 _sqlite/connection.c _sqlite/cursor.c _sqlite/microprotocols.c _sqlite/module.c _sqlite/prepare_protocol.c _sqlite/row.c _sqlite/statement.c _sqlite/util.c -lsqlite3
diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c
index 4cbbac3326a8a..c0371fb3f3b20 100644
--- a/Modules/_dbmmodule.c
+++ b/Modules/_dbmmodule.c
@@ -12,20 +12,26 @@
 /* Some Linux systems install gdbm/ndbm.h, but not ndbm.h.  This supports
  * whichever configure was able to locate.
  */
-#if defined(HAVE_NDBM_H)
-#include <ndbm.h>
-static const char which_dbm[] = "GNU gdbm";  /* EMX port of GDBM */
-#elif defined(HAVE_GDBM_NDBM_H)
-#include <gdbm/ndbm.h>
-static const char which_dbm[] = "GNU gdbm";
-#elif defined(HAVE_GDBM_DASH_NDBM_H)
-#include <gdbm-ndbm.h>
-static const char which_dbm[] = "GNU gdbm";
-#elif defined(HAVE_BERKDB_H)
-#include <db.h>
-static const char which_dbm[] = "Berkeley DB";
+#if defined(USE_NDBM)
+  #include <ndbm.h>
+  static const char which_dbm[] = "GNU gdbm";  /* EMX port of GDBM */
+#elif defined(USE_GDBM_COMPAT)
+  #ifdef HAVE_GDBM_NDBM_H
+    #include <gdbm/ndbm.h>
+  #elif HAVE_GDBM_DASH_NDBM_H
+    #include <gdbm-ndbm.h>
+  #else
+    #error "No gdbm/ndbm.h or gdbm-ndbm.h available"
+  #endif
+  static const char which_dbm[] = "GNU gdbm";
+#elif defined(USE_BERKDB)
+  #ifndef DB_DBM_HSEARCH
+    #define DB_DBM_HSEARCH 1
+  #endif
+  #include <db.h>
+  static const char which_dbm[] = "Berkeley DB";
 #else
-#error "No ndbm.h available!"
+  #error "No ndbm.h available!"
 #endif
 
 typedef struct {
diff --git a/configure b/configure
index d9c41226a3550..2a89703d29475 100755
--- a/configure
+++ b/configure
@@ -10822,6 +10822,340 @@ else
   TCLTK_LIBS="$with_tcltk_libs"
 fi
 
+# check for _gdbmmodulec dependencies
+for ac_header in gdbm.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "gdbm.h" "ac_cv_header_gdbm_h" "$ac_includes_default"
+if test "x$ac_cv_header_gdbm_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GDBM_H 1
+_ACEOF
+
+  LIBS_SAVE=$LIBS
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gdbm_open in -lgdbm" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm... " >&6; }
+if ${ac_cv_lib_gdbm_gdbm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgdbm  $LIBS"
+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.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gdbm_open ();
+int
+main ()
+{
+return gdbm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gdbm_gdbm_open=yes
+else
+  ac_cv_lib_gdbm_gdbm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_gdbm_open" >&5
+$as_echo "$ac_cv_lib_gdbm_gdbm_open" >&6; }
+if test "x$ac_cv_lib_gdbm_gdbm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBGDBM 1
+_ACEOF
+
+  LIBS="-lgdbm $LIBS"
+
+fi
+
+  LIBS=$LIBS_SAVE
+
+fi
+
+done
+
+
+# check for _dbmmodule.c dependencies
+for ac_header in ndbm.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "ndbm.h" "ac_cv_header_ndbm_h" "$ac_includes_default"
+if test "x$ac_cv_header_ndbm_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_NDBM_H 1
+_ACEOF
+
+  LIBS_SAVE="$LIBS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lndbm" >&5
+$as_echo_n "checking for dbm_open in -lndbm... " >&6; }
+if ${ac_cv_lib_ndbm_dbm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lndbm  $LIBS"
+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.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbm_open ();
+int
+main ()
+{
+return dbm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ndbm_dbm_open=yes
+else
+  ac_cv_lib_ndbm_dbm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ndbm_dbm_open" >&5
+$as_echo "$ac_cv_lib_ndbm_dbm_open" >&6; }
+if test "x$ac_cv_lib_ndbm_dbm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNDBM 1
+_ACEOF
+
+  LIBS="-lndbm $LIBS"
+
+fi
+
+  LIBS="$LIBS_SAVE"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lgdbm_compat" >&5
+$as_echo_n "checking for dbm_open in -lgdbm_compat... " >&6; }
+if ${ac_cv_lib_gdbm_compat_dbm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgdbm_compat  $LIBS"
+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.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbm_open ();
+int
+main ()
+{
+return dbm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gdbm_compat_dbm_open=yes
+else
+  ac_cv_lib_gdbm_compat_dbm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_compat_dbm_open" >&5
+$as_echo "$ac_cv_lib_gdbm_compat_dbm_open" >&6; }
+if test "x$ac_cv_lib_gdbm_compat_dbm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBGDBM_COMPAT 1
+_ACEOF
+
+  LIBS="-lgdbm_compat $LIBS"
+
+fi
+
+  LIBS="$LIBS_SAVE"
+
+fi
+
+done
+
+
+# "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h"
+# unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits.
+{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;}
+if ${ac_cv_header_gdbm_slash_ndbm_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+  ac_fn_c_check_header_mongrel "$LINENO" "gdbm/ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default"
+if test "x$ac_cv_header_gdbm_ndbm_h" = xyes; then :
+  ac_cv_header_gdbm_slash_ndbm_h=yes
+else
+  ac_cv_header_gdbm_slash_ndbm_h=no
+
+fi
+
+
+
+fi
+
+if test "x$ac_cv_header_gdbm_slash_ndbm_h" = xyes; then :
+
+
+$as_echo "#define HAVE_GDBM_NDBM_H 1" >>confdefs.h
+
+
+fi
+
+{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;}
+if ${ac_cv_header_gdbm_dash_ndbm_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+  ac_fn_c_check_header_mongrel "$LINENO" "gdbm-ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default"
+if test "x$ac_cv_header_gdbm_ndbm_h" = xyes; then :
+  ac_cv_header_gdbm_dash_ndbm_h=yes
+else
+  ac_cv_header_gdbm_dash_ndbm_h=no
+
+fi
+
+
+
+fi
+
+if test "x$ac_cv_header_gdbm_dash_ndbm_h" = xyes; then :
+
+
+$as_echo "#define HAVE_GDBM_DASH_NDBM_H 1" >>confdefs.h
+
+
+fi
+{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;}
+
+if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then
+  LIBS_SAVE="$LIBS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbm_open in -lgdbm_compat" >&5
+$as_echo_n "checking for dbm_open in -lgdbm_compat... " >&6; }
+if ${ac_cv_lib_gdbm_compat_dbm_open+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgdbm_compat  $LIBS"
+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.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbm_open ();
+int
+main ()
+{
+return dbm_open ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gdbm_compat_dbm_open=yes
+else
+  ac_cv_lib_gdbm_compat_dbm_open=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_compat_dbm_open" >&5
+$as_echo "$ac_cv_lib_gdbm_compat_dbm_open" >&6; }
+if test "x$ac_cv_lib_gdbm_compat_dbm_open" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBGDBM_COMPAT 1
+_ACEOF
+
+  LIBS="-lgdbm_compat $LIBS"
+
+fi
+
+  LIBS="$LIBS_SAVE"
+fi
+
+# Check for libdb >= 5 with dbm_open()
+# db.h re-defines the name of the function
+for ac_header in db.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "db.h" "ac_cv_header_db_h" "$ac_includes_default"
+if test "x$ac_cv_header_db_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DB_H 1
+_ACEOF
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdb" >&5
+$as_echo_n "checking for libdb... " >&6; }
+if ${ac_cv_have_libdb+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    LIBS_SAVE="$LIBS"
+    LIBS="$LIBS -ldb"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+      #define DB_DBM_HSEARCH 1
+      #include <db.h>
+      #if DB_VERSION_MAJOR < 5
+        #error "dh.h: DB_VERSION_MAJOR < 5 is not supported."
+      #endif
+
+int
+main ()
+{
+DBM *dbm = dbm_open(NULL, 0, 0)
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_have_libdb=yes
+else
+  ac_cv_have_libdb=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LIBS="$LIBS_SAVE"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5
+$as_echo "$ac_cv_have_libdb" >&6; }
+  if test "x$ac_cv_have_libdb" = xyes; then :
+
+
+$as_echo "#define HAVE_LIBDB 1" >>confdefs.h
+
+
+fi
+
+fi
+
+done
+
+
 # Check for --with-dbmliborder
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dbmliborder" >&5
 $as_echo_n "checking for --with-dbmliborder... " >&6; }
@@ -10833,12 +11167,15 @@ if test x$with_dbmliborder = xyes
 then
 as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5
 else
-  for db in `echo $with_dbmliborder | sed 's/:/ /g'`; do
+  as_save_IFS=$IFS
+  IFS=:
+  for db in $with_dbmliborder; do
     if test x$db != xndbm && test x$db != xgdbm && test x$db != xbdb
     then
       as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5
     fi
   done
+  IFS=$as_save_IFS
 fi
 fi
 
diff --git a/configure.ac b/configure.ac
index cfd7184ac3aff..4817422178df7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3094,6 +3094,74 @@ else
   TCLTK_LIBS="$with_tcltk_libs"
 fi
 
+# check for _gdbmmodulec dependencies
+AC_CHECK_HEADERS([gdbm.h], [
+  LIBS_SAVE=$LIBS
+  AC_CHECK_LIB([gdbm], [gdbm_open])
+  LIBS=$LIBS_SAVE
+])
+
+# check for _dbmmodule.c dependencies
+AC_CHECK_HEADERS([ndbm.h], [
+  LIBS_SAVE="$LIBS"
+  AC_CHECK_LIB([ndbm], [dbm_open])
+  LIBS="$LIBS_SAVE"
+  AC_CHECK_LIB([gdbm_compat], [dbm_open])
+  LIBS="$LIBS_SAVE"
+])
+
+# "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h"
+# unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits.
+AS_UNSET([ac_cv_header_gdbm_ndbm_h])
+AC_CACHE_VAL([ac_cv_header_gdbm_slash_ndbm_h], [
+  AC_CHECK_HEADER(
+    [gdbm/ndbm.h],
+    [ac_cv_header_gdbm_slash_ndbm_h=yes], [ac_cv_header_gdbm_slash_ndbm_h=no]
+  )
+])
+AS_VAR_IF([ac_cv_header_gdbm_slash_ndbm_h], [yes], [
+  AC_DEFINE([HAVE_GDBM_NDBM_H], [1], [Define to 1 if you have the <gdbm/ndbm.h> header file.])
+])
+
+AS_UNSET([ac_cv_header_gdbm_ndbm_h])
+AC_CACHE_VAL([ac_cv_header_gdbm_dash_ndbm_h], [
+  AC_CHECK_HEADER(
+    [gdbm-ndbm.h],
+    [ac_cv_header_gdbm_dash_ndbm_h=yes], [ac_cv_header_gdbm_dash_ndbm_h=no]
+  )
+])
+AS_VAR_IF([ac_cv_header_gdbm_dash_ndbm_h], [yes], [
+  AC_DEFINE([HAVE_GDBM_DASH_NDBM_H], [1], [Define to 1 if you have the <gdbm-ndbm.h> header file.])
+])
+AS_UNSET([ac_cv_header_gdbm_ndbm_h])
+
+if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then
+  LIBS_SAVE="$LIBS"
+  AC_CHECK_LIB([gdbm_compat], [dbm_open])
+  LIBS="$LIBS_SAVE"
+fi
+
+# Check for libdb >= 5 with dbm_open()
+# db.h re-defines the name of the function
+AC_CHECK_HEADERS([db.h], [
+  AC_CACHE_CHECK([for libdb], [ac_cv_have_libdb], [
+    LIBS_SAVE="$LIBS"
+    LIBS="$LIBS -ldb"
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([
+      #define DB_DBM_HSEARCH 1
+      #include <db.h>
+      #if DB_VERSION_MAJOR < 5
+        #error "dh.h: DB_VERSION_MAJOR < 5 is not supported."
+      #endif
+      ], [DBM *dbm = dbm_open(NULL, 0, 0)])
+    ], [ac_cv_have_libdb=yes], [ac_cv_have_libdb=no])
+    LIBS="$LIBS_SAVE"
+  ])
+  AS_VAR_IF([ac_cv_have_libdb], [yes], [
+    AC_DEFINE([HAVE_LIBDB], [1], [Define to 1 if you have the `db' library (-ldb).])
+  ])
+])
+
 # Check for --with-dbmliborder
 AC_MSG_CHECKING(for --with-dbmliborder)
 AC_ARG_WITH(dbmliborder,
@@ -3103,12 +3171,15 @@ if test x$with_dbmliborder = xyes
 then
 AC_MSG_ERROR([proper usage is --with-dbmliborder=db1:db2:...])
 else
-  for db in `echo $with_dbmliborder | sed 's/:/ /g'`; do
+  as_save_IFS=$IFS
+  IFS=:
+  for db in $with_dbmliborder; do
     if test x$db != xndbm && test x$db != xgdbm && test x$db != xbdb
     then
       AC_MSG_ERROR([proper usage is --with-dbmliborder=db1:db2:...])
     fi
   done
+  IFS=$as_save_IFS
 fi])
 AC_MSG_RESULT($with_dbmliborder)
 
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 2f71dd1758dcd..cbab59b739f31 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -214,6 +214,9 @@
 /* Define if you have the 'wchgat' function. */
 #undef HAVE_CURSES_WCHGAT
 
+/* Define to 1 if you have the <db.h> header file. */
+#undef HAVE_DB_H
+
 /* Define to 1 if you have the declaration of `RTLD_DEEPBIND', and to 0 if you
    don't. */
 #undef HAVE_DECL_RTLD_DEEPBIND
@@ -420,6 +423,15 @@
 /* Define if your compiler provides __uint128_t */
 #undef HAVE_GCC_UINT128_T
 
+/* Define to 1 if you have the <gdbm-ndbm.h> header file. */
+#undef HAVE_GDBM_DASH_NDBM_H
+
+/* Define to 1 if you have the <gdbm.h> header file. */
+#undef HAVE_GDBM_H
+
+/* Define to 1 if you have the <gdbm/ndbm.h> header file. */
+#undef HAVE_GDBM_NDBM_H
+
 /* Define if you have the getaddrinfo function. */
 #undef HAVE_GETADDRINFO
 
@@ -586,12 +598,21 @@
 /* Define to 1 if you have the `bz2' library (-lbz2). */
 #undef HAVE_LIBBZ2
 
+/* Define to 1 if you have the `db' library (-ldb). */
+#undef HAVE_LIBDB
+
 /* Define to 1 if you have the `dl' library (-ldl). */
 #undef HAVE_LIBDL
 
 /* Define to 1 if you have the `dld' library (-ldld). */
 #undef HAVE_LIBDLD
 
+/* Define to 1 if you have the `gdbm' library (-lgdbm). */
+#undef HAVE_LIBGDBM
+
+/* Define to 1 if you have the `gdbm_compat' library (-lgdbm_compat). */
+#undef HAVE_LIBGDBM_COMPAT
+
 /* Define to 1 if you have the `ieee' library (-lieee). */
 #undef HAVE_LIBIEEE
 
@@ -601,6 +622,9 @@
 /* Define to 1 if you have the `lzma' library (-llzma). */
 #undef HAVE_LIBLZMA
 
+/* Define to 1 if you have the `ndbm' library (-lndbm). */
+#undef HAVE_LIBNDBM
+
 /* Define to build the readline module. */
 #undef HAVE_LIBREADLINE
 
@@ -733,6 +757,9 @@
 /* Define to 1 if you have the <ncurses.h> header file. */
 #undef HAVE_NCURSES_H
 
+/* Define to 1 if you have the <ndbm.h> header file. */
+#undef HAVE_NDBM_H
+
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #undef HAVE_NDIR_H
 
diff --git a/setup.py b/setup.py
index 7fe7d27b14ce0..771ab5656311e 100644
--- a/setup.py
+++ b/setup.py
@@ -1221,208 +1221,19 @@ def detect_dbm_gdbm(self):
         # implementation independent wrapper for these; dbm/dumb.py provides
         # similar functionality (but slower of course) implemented in Python.
 
-        # Sleepycat^WOracle Berkeley DB interface.
-        #  https://www.oracle.com/database/technologies/related/berkeleydb.html
-        #
-        # This requires the Sleepycat^WOracle DB code. The supported versions
-        # are set below.  Visit the URL above to download
-        # a release.  Most open source OSes come with one or more
-        # versions of BerkeleyDB already installed.
-
-        max_db_ver = (5, 3)
-        min_db_ver = (3, 3)
-        db_setup_debug = False   # verbose debug prints from this script?
-
-        def allow_db_ver(db_ver):
-            """Returns a boolean if the given BerkeleyDB version is acceptable.
-
-            Args:
-              db_ver: A tuple of the version to verify.
-            """
-            if not (min_db_ver <= db_ver <= max_db_ver):
-                return False
-            return True
-
-        def gen_db_minor_ver_nums(major):
-            if major == 4:
-                for x in range(max_db_ver[1]+1):
-                    if allow_db_ver((4, x)):
-                        yield x
-            elif major == 3:
-                for x in (3,):
-                    if allow_db_ver((3, x)):
-                        yield x
-            else:
-                raise ValueError("unknown major BerkeleyDB version", major)
-
-        # construct a list of paths to look for the header file in on
-        # top of the normal inc_dirs.
-        db_inc_paths = [
-            '/usr/include/db4',
-            '/usr/local/include/db4',
-            '/opt/sfw/include/db4',
-            '/usr/include/db3',
-            '/usr/local/include/db3',
-            '/opt/sfw/include/db3',
-            # Fink defaults (https://www.finkproject.org/)
-            '/sw/include/db4',
-            '/sw/include/db3',
-        ]
-        # 4.x minor number specific paths
-        for x in gen_db_minor_ver_nums(4):
-            db_inc_paths.append('/usr/include/db4%d' % x)
-            db_inc_paths.append('/usr/include/db4.%d' % x)
-            db_inc_paths.append('/usr/local/BerkeleyDB.4.%d/include' % x)
-            db_inc_paths.append('/usr/local/include/db4%d' % x)
-            db_inc_paths.append('/pkg/db-4.%d/include' % x)
-            db_inc_paths.append('/opt/db-4.%d/include' % x)
-            # MacPorts default (https://www.macports.org/)
-            db_inc_paths.append('/opt/local/include/db4%d' % x)
-        # 3.x minor number specific paths
-        for x in gen_db_minor_ver_nums(3):
-            db_inc_paths.append('/usr/include/db3%d' % x)
-            db_inc_paths.append('/usr/local/BerkeleyDB.3.%d/include' % x)
-            db_inc_paths.append('/usr/local/include/db3%d' % x)
-            db_inc_paths.append('/pkg/db-3.%d/include' % x)
-            db_inc_paths.append('/opt/db-3.%d/include' % x)
-
-        if CROSS_COMPILING:
-            db_inc_paths = []
-
-        # Add some common subdirectories for Sleepycat DB to the list,
-        # based on the standard include directories. This way DB3/4 gets
-        # picked up when it is installed in a non-standard prefix and
-        # the user has added that prefix into inc_dirs.
-        std_variants = []
-        for dn in self.inc_dirs:
-            std_variants.append(os.path.join(dn, 'db3'))
-            std_variants.append(os.path.join(dn, 'db4'))
-            for x in gen_db_minor_ver_nums(4):
-                std_variants.append(os.path.join(dn, "db4%d"%x))
-                std_variants.append(os.path.join(dn, "db4.%d"%x))
-            for x in gen_db_minor_ver_nums(3):
-                std_variants.append(os.path.join(dn, "db3%d"%x))
-                std_variants.append(os.path.join(dn, "db3.%d"%x))
-
-        db_inc_paths = std_variants + db_inc_paths
-        db_inc_paths = [p for p in db_inc_paths if os.path.exists(p)]
-
-        db_ver_inc_map = {}
-
-        if MACOS:
-            sysroot = macosx_sdk_root()
-
-        class db_found(Exception): pass
-        try:
-            # See whether there is a Sleepycat header in the standard
-            # search path.
-            for d in self.inc_dirs + db_inc_paths:
-                f = os.path.join(d, "db.h")
-                if MACOS and is_macosx_sdk_path(d):
-                    f = os.path.join(sysroot, d[1:], "db.h")
-
-                if db_setup_debug: print("db: looking for db.h in", f)
-                if os.path.exists(f):
-                    with open(f, 'rb') as file:
-                        f = file.read()
-                    m = re.search(br"#define\WDB_VERSION_MAJOR\W(\d+)", f)
-                    if m:
-                        db_major = int(m.group(1))
-                        m = re.search(br"#define\WDB_VERSION_MINOR\W(\d+)", f)
-                        db_minor = int(m.group(1))
-                        db_ver = (db_major, db_minor)
-
-                        # Avoid 4.6 prior to 4.6.21 due to a BerkeleyDB bug
-                        if db_ver == (4, 6):
-                            m = re.search(br"#define\WDB_VERSION_PATCH\W(\d+)", f)
-                            db_patch = int(m.group(1))
-                            if db_patch < 21:
-                                print("db.h:", db_ver, "patch", db_patch,
-                                      "being ignored (4.6.x must be >= 4.6.21)")
-                                continue
-
-                        if ( (db_ver not in db_ver_inc_map) and
-                            allow_db_ver(db_ver) ):
-                            # save the include directory with the db.h version
-                            # (first occurrence only)
-                            db_ver_inc_map[db_ver] = d
-                            if db_setup_debug:
-                                print("db.h: found", db_ver, "in", d)
-                        else:
-                            # we already found a header for this library version
-                            if db_setup_debug: print("db.h: ignoring", d)
-                    else:
-                        # ignore this header, it didn't contain a version number
-                        if db_setup_debug:
-                            print("db.h: no version number version in", d)
-
-            db_found_vers = list(db_ver_inc_map.keys())
-            db_found_vers.sort()
-
-            while db_found_vers:
-                db_ver = db_found_vers.pop()
-                db_incdir = db_ver_inc_map[db_ver]
-
-                # check lib directories parallel to the location of the header
-                db_dirs_to_check = [
-                    db_incdir.replace("include", 'lib64'),
-                    db_incdir.replace("include", 'lib'),
-                ]
-
-                if not MACOS:
-                    db_dirs_to_check = list(filter(os.path.isdir, db_dirs_to_check))
-
-                else:
-                    # Same as other branch, but takes OSX SDK into account
-                    tmp = []
-                    for dn in db_dirs_to_check:
-                        if is_macosx_sdk_path(dn):
-                            if os.path.isdir(os.path.join(sysroot, dn[1:])):
-                                tmp.append(dn)
-                        else:
-                            if os.path.isdir(dn):
-                                tmp.append(dn)
-                    db_dirs_to_check = tmp
-
-                    db_dirs_to_check = tmp
-
-                # Look for a version specific db-X.Y before an ambiguous dbX
-                # XXX should we -ever- look for a dbX name?  Do any
-                # systems really not name their library by version and
-                # symlink to more general names?
-                for dblib in (('db-%d.%d' % db_ver),
-                              ('db%d%d' % db_ver),
-                              ('db%d' % db_ver[0])):
-                    dblib_file = self.compiler.find_library_file(
-                                    db_dirs_to_check + self.lib_dirs, dblib )
-                    if dblib_file:
-                        dblib_dir = [ os.path.abspath(os.path.dirname(dblib_file)) ]
-                        raise db_found
-                    else:
-                        if db_setup_debug: print("db lib: ", dblib, "not found")
-
-        except db_found:
-            if db_setup_debug:
-                print("bsddb using BerkeleyDB lib:", db_ver, dblib)
-                print("bsddb lib dir:", dblib_dir, " inc dir:", db_incdir)
-            dblibs = [dblib]
-            # Only add the found library and include directories if they aren't
-            # already being searched. This avoids an explicit runtime library
-            # dependency.
-            if db_incdir in self.inc_dirs:
-                db_incs = None
-            else:
-                db_incs = [db_incdir]
-            if dblib_dir[0] in self.lib_dirs:
-                dblib_dir = None
-        else:
-            if db_setup_debug: print("db: no appropriate library found")
-            db_incs = None
-            dblibs = []
-            dblib_dir = None
-
         dbm_setup_debug = False   # verbose debug prints from this script?
         dbm_order = ['gdbm']
+
+        # libdb, gdbm and ndbm headers and libraries
+        have_ndbm_h = sysconfig.get_config_var("HAVE_NDBM_H")
+        have_gdbm_h = sysconfig.get_config_var("HAVE_GDBM_H")
+        have_gdbm_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_NDBM_H")
+        have_gdbm_dash_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_DASH_NDBM_H")
+        have_libndbm = sysconfig.get_config_var("HAVE_LIBNDBM")
+        have_libgdbm = sysconfig.get_config_var("HAVE_LIBGDBM")
+        have_libgdbm_compat = sysconfig.get_config_var("HAVE_LIBGDBM_COMPAT")
+        have_libdb = sysconfig.get_config_var("HAVE_LIBDB")
+
         # The standard Unix dbm module:
         if not CYGWIN:
             config_args = [arg.strip("'")
@@ -1436,61 +1247,40 @@ class db_found(Exception): pass
             dbmext = None
             for cand in dbm_order:
                 if cand == "ndbm":
-                    if find_file("ndbm.h", self.inc_dirs, []) is not None:
+                    if have_ndbm_h:
                         # Some systems have -lndbm, others have -lgdbm_compat,
                         # others don't have either
-                        if self.compiler.find_library_file(self.lib_dirs,
-                                                               'ndbm'):
+                        if have_libndbm:
                             ndbm_libs = ['ndbm']
-                        elif self.compiler.find_library_file(self.lib_dirs,
-                                                             'gdbm_compat'):
+                        elif have_libgdbm_compat:
                             ndbm_libs = ['gdbm_compat']
                         else:
                             ndbm_libs = []
                         if dbm_setup_debug: print("building dbm using ndbm")
-                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
-                                           define_macros=[
-                                               ('HAVE_NDBM_H',None),
-                                               ],
-                                           libraries=ndbm_libs)
+                        dbmext = Extension(
+                            '_dbm', ['_dbmmodule.c'],
+                            define_macros=[('USE_NDBM', None)],
+                            libraries=ndbm_libs
+                        )
                         break
-
                 elif cand == "gdbm":
-                    if self.compiler.find_library_file(self.lib_dirs, 'gdbm'):
-                        gdbm_libs = ['gdbm']
-                        if self.compiler.find_library_file(self.lib_dirs,
-                                                               'gdbm_compat'):
-                            gdbm_libs.append('gdbm_compat')
-                        if find_file("gdbm/ndbm.h", self.inc_dirs, []) is not None:
-                            if dbm_setup_debug: print("building dbm using gdbm")
-                            dbmext = Extension(
-                                '_dbm', ['_dbmmodule.c'],
-                                define_macros=[
-                                    ('HAVE_GDBM_NDBM_H', None),
-                                    ],
-                                libraries = gdbm_libs)
-                            break
-                        if find_file("gdbm-ndbm.h", self.inc_dirs, []) is not None:
-                            if dbm_setup_debug: print("building dbm using gdbm")
-                            dbmext = Extension(
-                                '_dbm', ['_dbmmodule.c'],
-                                define_macros=[
-                                    ('HAVE_GDBM_DASH_NDBM_H', None),
-                                    ],
-                                libraries = gdbm_libs)
-                            break
+                    # dbm_open() is provided by libgdbm_compat, which wraps libgdbm
+                    if have_libgdbm_compat and (have_gdbm_ndbm_h or have_gdbm_dash_ndbm_h):
+                        if dbm_setup_debug: print("building dbm using gdbm")
+                        dbmext = Extension(
+                            '_dbm', ['_dbmmodule.c'],
+                            define_macros=[('USE_GDBM_COMPAT', None)],
+                            libraries=['gdbm_compat']
+                        )
+                        break
                 elif cand == "bdb":
-                    if dblibs:
+                    if have_libdb:
                         if dbm_setup_debug: print("building dbm using bdb")
-                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
-                                           library_dirs=dblib_dir,
-                                           runtime_library_dirs=dblib_dir,
-                                           include_dirs=db_incs,
-                                           define_macros=[
-                                               ('HAVE_BERKDB_H', None),
-                                               ('DB_DBM_HSEARCH', None),
-                                               ],
-                                           libraries=dblibs)
+                        dbmext = Extension(
+                            '_dbm', ['_dbmmodule.c'],
+                            define_macros=[('USE_BERKDB', None)],
+                            libraries=['db']
+                        )
                         break
             if dbmext is not None:
                 self.add(dbmext)
@@ -1498,8 +1288,7 @@ class db_found(Exception): pass
                 self.missing.append('_dbm')
 
         # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
-        if ('gdbm' in dbm_order and
-            self.compiler.find_library_file(self.lib_dirs, 'gdbm')):
+        if 'gdbm' in dbm_order and have_libgdbm:
             self.add(Extension('_gdbm', ['_gdbmmodule.c'],
                                libraries=['gdbm']))
         else:



More information about the Python-checkins mailing list