mirror of
https://github.com/python/cpython.git
synced 2024-11-23 01:45:25 +08:00
gh-113565: Improve and harden detection of curses dependencies (#119816)
1. Use pkg-config to check for ncursesw/panelw. If that fails, use pkg-config to check for ncurses/panel. 2. Regardless of pkg-config output, search for curses/panel headers, so we're sure we have all defines in pyconfig.h. 3. Regardless of pkg-config output, check if libncurses or libncursesw contains the 'initscr' symbol; if it does _and_ pkg-config failed earlier, add the resulting -llib linker option to CURSES_LIBS. Ditto for 'update_panels' and PANEL_LIBS. 4. Wrap the rest of the checks with WITH_SAVE_ENV and make sure we're using updated LIBS and CPPFLAGS for those. Add the PY_CHECK_CURSES convenience macro.
This commit is contained in:
parent
bd473aa598
commit
f80376b129
@ -36,13 +36,21 @@
|
||||
#define NCURSES_OPAQUE 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#else
|
||||
#include <curses.h>
|
||||
#if defined(HAVE_NCURSESW_NCURSES_H)
|
||||
# include <ncursesw/ncurses.h>
|
||||
#elif defined(HAVE_NCURSESW_CURSES_H)
|
||||
# include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSES_NCURSES_H)
|
||||
# include <ncurses/ncurses.h>
|
||||
#elif defined(HAVE_NCURSES_CURSES_H)
|
||||
# include <ncurses/curses.h>
|
||||
#elif defined(HAVE_NCURSES_H)
|
||||
# include <ncurses.h>
|
||||
#elif defined(HAVE_CURSES_H)
|
||||
# include <curses.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NCURSES_H
|
||||
#ifdef NCURSES_VERSION
|
||||
/* configure was checking <curses.h>, but we will
|
||||
use <ncurses.h>, which has some or all these features. */
|
||||
#if !defined(WINDOW_HAS_FLAGS) && \
|
||||
|
@ -0,0 +1,2 @@
|
||||
Improve :mod:`curses` and :mod:`curses.panel` dependency checks in
|
||||
:program:`configure`.
|
@ -19,7 +19,13 @@ static const char PyCursesVersion[] = "2.1";
|
||||
|
||||
#include "py_curses.h"
|
||||
|
||||
#include <panel.h>
|
||||
#if defined(HAVE_NCURSESW_PANEL_H)
|
||||
# include <ncursesw/panel.h>
|
||||
#elif defined(HAVE_NCURSES_PANEL_H)
|
||||
# include <ncurses/panel.h>
|
||||
#elif defined(HAVE_PANEL_H)
|
||||
# include <panel.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject *PyCursesError;
|
||||
|
@ -128,7 +128,7 @@ static const char PyCursesVersion[] = "2.2";
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_NCURSES_H) && (defined(sgi) || defined(__sun) || defined(SCO5))
|
||||
#if !defined(NCURSES_VERSION) && (defined(sgi) || defined(__sun) || defined(SCO5))
|
||||
#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
|
||||
typedef chtype attr_t; /* No attr_t type is available */
|
||||
#endif
|
||||
|
197
configure.ac
197
configure.ac
@ -6663,55 +6663,88 @@ then
|
||||
[Define if year with century should be normalized for strftime.])
|
||||
fi
|
||||
|
||||
dnl check for ncurses/ncursesw and panel/panelw
|
||||
dnl check for ncursesw/ncurses and panelw/panel
|
||||
dnl NOTE: old curses is not detected.
|
||||
dnl have_curses=[no, ncursesw, ncurses]
|
||||
dnl have_panel=[no, panelw, panel]
|
||||
dnl have_curses=[no, yes]
|
||||
dnl have_panel=[no, yes]
|
||||
have_curses=no
|
||||
have_panel=no
|
||||
|
||||
AH_TEMPLATE([HAVE_NCURSESW], [Define to 1 if you have the `ncursesw' library.])
|
||||
AC_CHECK_HEADERS([curses.h ncurses.h])
|
||||
dnl PY_CHECK_CURSES(LIBCURSES, LIBPANEL)
|
||||
dnl Sets 'have_curses' and 'have_panel'.
|
||||
dnl For the PKG_CHECK_MODULES() calls, we can safely reuse the first variable
|
||||
dnl here, since we're only calling the macro a second time if the first call
|
||||
dnl fails.
|
||||
AC_DEFUN([PY_CHECK_CURSES], [dnl
|
||||
AS_VAR_PUSHDEF([curses_var], [m4_toupper([$1])])
|
||||
AS_VAR_PUSHDEF([panel_var], [m4_toupper([$2])])
|
||||
PKG_CHECK_MODULES([CURSES], [$1],
|
||||
[AC_DEFINE([HAVE_]curses_var, [1], [Define if you have the '$1' library])
|
||||
AS_VAR_SET([have_curses], [yes])
|
||||
PKG_CHECK_MODULES([PANEL], [$2],
|
||||
[AC_DEFINE([HAVE_]panel_var, [1], [Define if you have the '$2' library])
|
||||
AS_VAR_SET([have_panel], [yes])],
|
||||
[AS_VAR_SET([have_panel], [no])])],
|
||||
[AS_VAR_SET([have_curses], [no])])
|
||||
AS_VAR_POPDEF([curses_var])
|
||||
AS_VAR_POPDEF([panel_var])])
|
||||
|
||||
AS_VAR_IF([ac_cv_header_ncurses_h], [yes], [
|
||||
if test "$ac_sys_system" != "Darwin"; then
|
||||
dnl On macOS, there is no separate /usr/lib/libncursesw nor libpanelw.
|
||||
PKG_CHECK_MODULES([CURSES], [ncursesw], [
|
||||
AC_DEFINE([HAVE_NCURSESW], [1])
|
||||
have_curses=ncursesw
|
||||
], [
|
||||
WITH_SAVE_ENV([
|
||||
AC_CHECK_LIB([ncursesw], [initscr], [
|
||||
AC_DEFINE([HAVE_NCURSESW], [1])
|
||||
have_curses=ncursesw
|
||||
CURSES_CFLAGS=${CURSES_CFLAGS-""}
|
||||
CURSES_LIBS=${CURSES_LIBS-"-lncursesw"}
|
||||
])
|
||||
])
|
||||
])
|
||||
fi
|
||||
# Check for ncursesw/panelw first. If that fails, try ncurses/panel.
|
||||
PY_CHECK_CURSES([ncursesw], [panelw])
|
||||
AS_VAR_IF([have_curses], [no],
|
||||
[PY_CHECK_CURSES([ncurses], [panel])])
|
||||
|
||||
AS_VAR_IF([have_curses], [no], [
|
||||
PKG_CHECK_MODULES([CURSES], [ncurses], [
|
||||
have_curses=ncurses
|
||||
], [
|
||||
WITH_SAVE_ENV([
|
||||
AC_CHECK_LIB([ncurses], [initscr], [
|
||||
have_curses=ncurses
|
||||
CURSES_CFLAGS=${CURSES_CFLAGS-""}
|
||||
CURSES_LIBS=${CURSES_LIBS-"-lncurses"}
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
WITH_SAVE_ENV([
|
||||
# Make sure we've got the header defines.
|
||||
AS_VAR_APPEND([CPPFLAGS], [" $CURSES_CFLAGS $PANEL_CFLAGS"])
|
||||
AC_CHECK_HEADERS(m4_normalize([
|
||||
ncursesw/curses.h ncursesw/ncurses.h ncursesw/panel.h
|
||||
ncurses/curses.h ncurses/ncurses.h ncurses/panel.h
|
||||
curses.h ncurses.h panel.h
|
||||
]))
|
||||
|
||||
])dnl ac_cv_header_ncurses_h = yes
|
||||
# Check that we're able to link with crucial curses/panel functions. This
|
||||
# also serves as a fallback in case pkg-config failed.
|
||||
AS_VAR_APPEND([LIBS], [" $CURSES_LIBS $PANEL_LIBS"])
|
||||
AC_SEARCH_LIBS([initscr], [ncursesw ncurses],
|
||||
[AS_VAR_IF([have_curses], [no],
|
||||
[AS_VAR_SET([have_curses], [yes])
|
||||
CURSES_LIBS=${CURSES_LIBS-"$ac_cv_search_initscr"}])],
|
||||
[AS_VAR_SET([have_curses], [no])])
|
||||
AC_SEARCH_LIBS([update_panels], [panelw panel],
|
||||
[AS_VAR_IF([have_panel], [no],
|
||||
[AS_VAR_SET([have_panel], [yes])
|
||||
PANEL_LIBS=${PANEL_LIBS-"$ac_cv_search_update_panels"}])],
|
||||
[AS_VAR_SET([have_panel], [no])])
|
||||
|
||||
dnl Issue #25720: ncurses has introduced the NCURSES_OPAQUE symbol making opaque
|
||||
dnl structs since version 5.7. If the macro is defined as zero before including
|
||||
dnl [n]curses.h, ncurses will expose fields of the structs regardless of the
|
||||
dnl configuration.
|
||||
AC_DEFUN([_CURSES_INCLUDES],dnl
|
||||
[
|
||||
#define NCURSES_OPAQUE 0
|
||||
#if defined(HAVE_NCURSESW_NCURSES_H)
|
||||
# include <ncursesw/ncurses.h>
|
||||
#elif defined(HAVE_NCURSESW_CURSES_H)
|
||||
# include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSES_NCURSES_H)
|
||||
# include <ncurses/ncurses.h>
|
||||
#elif defined(HAVE_NCURSES_CURSES_H)
|
||||
# include <ncurses/curses.h>
|
||||
#elif defined(HAVE_NCURSES_H)
|
||||
# include <ncurses.h>
|
||||
#elif defined(HAVE_CURSES_H)
|
||||
# include <curses.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AS_IF([test "have_curses" != "no"], [
|
||||
dnl remove _XOPEN_SOURCE macro from curses cflags. pyconfig.h sets
|
||||
dnl the macro to 700.
|
||||
CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g')
|
||||
|
||||
if test "$have_curses" != no -a "$ac_sys_system" = "Darwin"; then
|
||||
AS_VAR_IF([ac_sys_system], [Darwin], [
|
||||
dnl On macOS, there is no separate /usr/lib/libncursesw nor libpanelw.
|
||||
dnl System-supplied ncurses combines libncurses/libpanel and supports wide
|
||||
dnl characters, so we can use it like ncursesw.
|
||||
@ -6721,82 +6754,17 @@ if test "$have_curses" != no -a "$ac_sys_system" = "Darwin"; then
|
||||
dnl _XOPEN_SOURCE_EXTENDED here for ncurses wide char support.
|
||||
|
||||
AS_VAR_APPEND([CURSES_CFLAGS], [" -D_XOPEN_SOURCE_EXTENDED=1"])
|
||||
AC_DEFINE([HAVE_NCURSESW], [1])
|
||||
fi
|
||||
|
||||
dnl TODO: detect "curses" and special cases tinfo, terminfo, or termcap
|
||||
|
||||
AC_MSG_CHECKING([curses module flags])
|
||||
AS_VAR_IF([have_curses], [no], [
|
||||
AC_MSG_RESULT([no])
|
||||
], [
|
||||
AC_MSG_RESULT([$have_curses (CFLAGS: $CURSES_CFLAGS, LIBS: $CURSES_LIBS)])
|
||||
])
|
||||
|
||||
dnl check for ncurses' panel/panelw library
|
||||
AC_CHECK_HEADERS([panel.h])
|
||||
|
||||
AS_VAR_IF([ac_cv_header_panel_h], [yes], [
|
||||
|
||||
if test "$ac_sys_system" != "Darwin"; then
|
||||
dnl On macOS, there is no separate /usr/lib/libncursesw nor libpanelw.
|
||||
AS_VAR_IF([have_curses], [ncursesw], [
|
||||
PKG_CHECK_MODULES([PANEL], [panelw], [
|
||||
have_panel=panelw
|
||||
], [
|
||||
WITH_SAVE_ENV([
|
||||
AC_CHECK_LIB([panelw], [update_panels], [
|
||||
have_panel=panelw
|
||||
PANEL_CFLAGS=${PANEL_CFLAGS-""}
|
||||
PANEL_LIBS=${PANEL_LIBS-"-lpanelw"}
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
fi
|
||||
|
||||
AS_VAR_IF([have_curses], [ncurses], [
|
||||
PKG_CHECK_MODULES([PANEL], [panel], [
|
||||
have_panel=panel
|
||||
], [
|
||||
WITH_SAVE_ENV([
|
||||
AC_CHECK_LIB([panel], [update_panels], [
|
||||
have_panel=panel
|
||||
PANEL_CFLAGS=${PANEL_CFLAGS-""}
|
||||
PANEL_LIBS=${PANEL_LIBS-"-lpanel"}
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
])dnl ac_cv_header_panel_h = yes
|
||||
|
||||
dnl pyconfig.h defines _XOPEN_SOURCE=700
|
||||
PANEL_CFLAGS=$(echo $PANEL_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g')
|
||||
|
||||
AC_MSG_CHECKING([panel flags])
|
||||
AS_VAR_IF([have_panel], [no], [
|
||||
AC_MSG_RESULT([no])
|
||||
], [
|
||||
AC_MSG_RESULT([$have_panel (CFLAGS: $PANEL_CFLAGS, LIBS: $PANEL_LIBS)])
|
||||
])
|
||||
|
||||
# first curses header check
|
||||
ac_save_cppflags="$CPPFLAGS"
|
||||
if test "$cross_compiling" = no; then
|
||||
CPPFLAGS="$CPPFLAGS -I/usr/include/ncursesw"
|
||||
fi
|
||||
|
||||
# On Solaris, term.h requires curses.h
|
||||
AC_CHECK_HEADERS([term.h], [], [], [
|
||||
#ifdef HAVE_CURSES_H
|
||||
#include <curses.h>
|
||||
#endif
|
||||
])
|
||||
AC_CHECK_HEADERS([term.h], [], [], _CURSES_INCLUDES)
|
||||
|
||||
# On HP/UX 11.0, mvwdelch is a block with a return statement
|
||||
AC_CACHE_CHECK([whether mvwdelch is an expression], [ac_cv_mvwdelch_is_expression],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <curses.h>]], [[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(_CURSES_INCLUDES, [[
|
||||
int rtn;
|
||||
rtn = mvwdelch(0,0,0);
|
||||
]])],
|
||||
@ -6809,15 +6777,8 @@ then
|
||||
[Define if mvwdelch in curses.h is an expression.])
|
||||
fi
|
||||
|
||||
# Issue #25720: ncurses has introduced the NCURSES_OPAQUE symbol making opaque
|
||||
# structs since version 5.7. If the macro is defined as zero before including
|
||||
# [n]curses.h, ncurses will expose fields of the structs regardless of the
|
||||
# configuration.
|
||||
AC_CACHE_CHECK([whether WINDOW has _flags], [ac_cv_window_has_flags],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#define NCURSES_OPAQUE 0
|
||||
#include <curses.h>
|
||||
]], [[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(_CURSES_INCLUDES, [[
|
||||
WINDOW *w;
|
||||
w->_flags = 0;
|
||||
]])],
|
||||
@ -6839,11 +6800,7 @@ AC_DEFUN([PY_CHECK_CURSES_FUNC],
|
||||
[for curses function $1],
|
||||
[py_var],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[
|
||||
#define NCURSES_OPAQUE 0
|
||||
#include <curses.h>
|
||||
], [
|
||||
[AC_LANG_PROGRAM(_CURSES_INCLUDES, [
|
||||
#ifndef $1
|
||||
void *x=$1
|
||||
#endif
|
||||
@ -6871,6 +6828,8 @@ PY_CHECK_CURSES_FUNC([has_key])
|
||||
PY_CHECK_CURSES_FUNC([typeahead])
|
||||
PY_CHECK_CURSES_FUNC([use_env])
|
||||
CPPFLAGS=$ac_save_cppflags
|
||||
])dnl have_curses != no
|
||||
])dnl save env
|
||||
|
||||
AC_MSG_NOTICE([checking for device files])
|
||||
|
||||
@ -7788,11 +7747,11 @@ PY_STDLIB_MOD([_ctypes],
|
||||
[], [test "$have_libffi" = yes],
|
||||
[$NO_STRICT_OVERFLOW_CFLAGS $LIBFFI_CFLAGS], [$LIBFFI_LIBS])
|
||||
PY_STDLIB_MOD([_curses],
|
||||
[], [test "$have_curses" != "no"],
|
||||
[], [test "$have_curses" = "yes"],
|
||||
[$CURSES_CFLAGS], [$CURSES_LIBS]
|
||||
)
|
||||
PY_STDLIB_MOD([_curses_panel],
|
||||
[], [test "$have_panel" != "no"],
|
||||
[], [test "$have_curses" = "yes" && test "$have_panel" = "yes"],
|
||||
[$PANEL_CFLAGS $CURSES_CFLAGS], [$PANEL_LIBS $CURSES_LIBS]
|
||||
)
|
||||
PY_STDLIB_MOD([_decimal],
|
||||
|
@ -829,12 +829,33 @@
|
||||
/* Define to 1 if you have the `nanosleep' function. */
|
||||
#undef HAVE_NANOSLEEP
|
||||
|
||||
/* Define to 1 if you have the `ncursesw' library. */
|
||||
/* Define if you have the 'ncurses' library */
|
||||
#undef HAVE_NCURSES
|
||||
|
||||
/* Define if you have the 'ncursesw' library */
|
||||
#undef HAVE_NCURSESW
|
||||
|
||||
/* Define to 1 if you have the <ncursesw/curses.h> header file. */
|
||||
#undef HAVE_NCURSESW_CURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
|
||||
#undef HAVE_NCURSESW_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncursesw/panel.h> header file. */
|
||||
#undef HAVE_NCURSESW_PANEL_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses/curses.h> header file. */
|
||||
#undef HAVE_NCURSES_CURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses.h> header file. */
|
||||
#undef HAVE_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
|
||||
#undef HAVE_NCURSES_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses/panel.h> header file. */
|
||||
#undef HAVE_NCURSES_PANEL_H
|
||||
|
||||
/* Define to 1 if you have the <ndbm.h> header file. */
|
||||
#undef HAVE_NDBM_H
|
||||
|
||||
@ -878,6 +899,12 @@
|
||||
/* Define to 1 if you have the `openpty' function. */
|
||||
#undef HAVE_OPENPTY
|
||||
|
||||
/* Define if you have the 'panel' library */
|
||||
#undef HAVE_PANEL
|
||||
|
||||
/* Define if you have the 'panelw' library */
|
||||
#undef HAVE_PANELW
|
||||
|
||||
/* Define to 1 if you have the <panel.h> header file. */
|
||||
#undef HAVE_PANEL_H
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user