Files
cpython/Misc/python-config.sh.in
Itamar Oren 3e13407763 gh-159819: Fix python-config.sh for installation paths containing spaces (#159820)
The shell `python-config` located its own prefix with unquoted command
substitutions, so any whitespace in the installation path made it print an
empty `--prefix` and `-I/include/...`-style paths while exiting 0.

- Quote the substitutions and the argument loop (POSIX `sh`, no bashisms).
- Exit 1 with a message when the script's directory cannot be resolved,
  instead of silently printing empty paths.
- Replace `sed "s#$prefix#$prefix_real#"` with a `relocate` helper using
  parameter expansion, so `#`, `&`, `\` and regex metacharacters in either
  prefix are handled literally. Same first-occurrence semantics.
- Add `test_python_config_sh_prefix_with_spaces`: runs the
  generated script from `…/path with spaces/bin/` and checks `--prefix`,
  `--exec-prefix`, `--includes` and empty stderr
2026-10-21 21:29:37 -07:00

140 lines
3.4 KiB
Bash

#!/bin/sh
# Keep this script in sync with python-config.in
exit_with_usage ()
{
local usage
usage="Usage: $0 --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed"
if [ "$1" -eq 0 ]; then
printf '%s\n' "$usage"
else
printf '%s\n' "$usage" >&2
fi
exit $1
}
if [ "$1" = "" ] ; then
exit_with_usage 1
fi
# Returns the actual prefix where this script was installed to.
# Fails if the directory containing this script cannot be resolved.
installed_prefix ()
{
RESULT=$(cd "$(dirname "$1")" && pwd -P) || return 1
RESULT=$(dirname "$RESULT")
if which readlink >/dev/null 2>&1 ; then
if readlink -f "$RESULT" >/dev/null 2>&1; then
RESULT=$(readlink -f "$RESULT")
fi
fi
printf '%s\n' "$RESULT"
}
prefix_real=$(installed_prefix "$0") || {
printf '%s\n' "$0: cannot determine the installation prefix" >&2
exit 1
}
# Fix paths from their built-to locations to their installed-to locations
# by replacing the first occurrence of the configured prefix with the actual
# one. Keep prefix & exec_prefix using their original values in case
# they are referenced in other configure variables, to prevent double
# substitution, issue #22140.
prefix="@prefix@"
exec_prefix="@exec_prefix@"
exec_prefix_real=${prefix_real}
relocate ()
{
case "$1" in
*"$prefix"*)
printf '%s\n' "${1%%"$prefix"*}${prefix_real}${1#*"$prefix"}"
;;
*)
printf '%s\n' "$1"
;;
esac
}
includedir=$(relocate "@includedir@")
libdir=$(relocate "@libdir@")
CFLAGS=$(relocate "@CFLAGS@")
VERSION="@VERSION@"
LIBM="@LIBM@"
LIBC="@LIBC@"
SYSLIBS="$LIBM $LIBC"
ABIFLAGS="@ABIFLAGS@"
LIBS="@LIBPYTHON@ @LIBS@ $SYSLIBS"
LIBS_EMBED="-lpython${VERSION}${ABIFLAGS} @LIBS@ $SYSLIBS"
BASECFLAGS="@BASECFLAGS@"
LDLIBRARY="@LDLIBRARY@"
OPT="@OPT@"
PY_ENABLE_SHARED="@PY_ENABLE_SHARED@"
LDVERSION="@LDVERSION@"
LIBDEST=${prefix_real}/lib/python${VERSION}
LIBPL=$(relocate "@LIBPL@")
SO="@EXT_SUFFIX@"
PYTHONFRAMEWORK="@PYTHONFRAMEWORK@"
INCDIR="-I$includedir/python${VERSION}${ABIFLAGS}"
PLATINCDIR="-I$includedir/python${VERSION}${ABIFLAGS}"
PY_EMBED=0
# Scan for --help or unknown argument.
for ARG in "$@"
do
case "$ARG" in
--help)
exit_with_usage 0
;;
--embed)
PY_EMBED=1
;;
--prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--abiflags|--configdir)
;;
*)
exit_with_usage 1
;;
esac
done
if [ $PY_EMBED = 1 ] ; then
LIBS="$LIBS_EMBED"
fi
for ARG in "$@"
do
case "$ARG" in
--prefix)
printf '%s\n' "$prefix_real"
;;
--exec-prefix)
printf '%s\n' "$exec_prefix_real"
;;
--includes)
printf '%s\n' "$INCDIR $PLATINCDIR"
;;
--cflags)
printf '%s\n' "$INCDIR $PLATINCDIR $BASECFLAGS $CFLAGS $OPT"
;;
--libs)
printf '%s\n' "$LIBS"
;;
--ldflags)
LIBPLUSED=
if [ "$PY_ENABLE_SHARED" = "0" ] ; then
LIBPLUSED="-L$LIBPL"
fi
printf '%s\n' "$LIBPLUSED -L$libdir $LIBS"
;;
--extension-suffix)
printf '%s\n' "$SO"
;;
--abiflags)
printf '%s\n' "$ABIFLAGS"
;;
--configdir)
printf '%s\n' "$LIBPL"
;;
esac
done