From b756b41ecb8fc097cd0076cca5d10854a9d35ab4 Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Tue, 27 Oct 2026 06:44:12 +0100 Subject: [PATCH] install: derive tclsh from --with-tcl when --with-tclsh is not set When Tcl is installed in a non-default location, the extension library is built against the tclConfig.sh designated by --with-tcl whereas the installed scripts run with the first tclsh found in PATH unless --with-tclsh is also passed. Such mismatch is not reported at build time and only shows up later through a library load failure or behavior differences. Look for the Tcl interpreter shell in the Tcl installation designated by --with-tcl before searching PATH: in the bin directory of the exec prefix recorded in tclConfig.sh, or in the bin directory sibling to the directory holding this script when it cannot be read. A version-suffixed tclsh is tried first as some installations do not provide the generic name. If no interpreter is found there, a warning is reported and the PATH lookup applies. An explicit --with-tclsh still takes precedence so both options can be decoupled when needed. The version-specific names tried by the PATH lookup now cover Tcl 9.0 and no longer Tcl 8.4, which is not supported anymore. Fixes #717 Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Xavier Delaruelle --- INSTALL.rst | 25 +++++++++++++++++++++ NEWS.rst | 11 ++++++++++ configure | 62 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/INSTALL.rst b/INSTALL.rst index 4ad0b7271..df633bcc8 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -1596,6 +1596,21 @@ instance :instopt:`--without-modulepath<--with-modulepath>`): compile Modules Tcl extension library if this file cannot be automatically found in default locations. + Unless :instopt:`--with-tclsh` is set, the Tcl interpreter shell is also + looked for in the Tcl installation designated by this option: ``tclsh`` is + searched in the ``bin`` directory of the installation prefix recorded in + ``tclConfig.sh`` (or in the ``bin`` directory sibling of the directory + holding this script when it cannot be read). This way :file:`modulecmd.tcl` + and other installed scripts run with the same Tcl the extension library is + built against. If no interpreter shell is found there, a warning is reported + and ``tclsh`` is looked for in standard binary paths. + + .. only:: html or latex + + .. versionchanged:: 5.8 + Tcl interpreter shell is looked for in designated Tcl installation + unless :instopt:`--with-tclsh` is set + .. instopt:: --with-tclinclude Directory containing the Tcl header files. Useful to compile Modules Tcl @@ -1606,10 +1621,20 @@ instance :instopt:`--without-modulepath<--with-modulepath>`): Name or full path of Tcl interpreter shell (default=\ ``tclsh``) + When this option is not set, ``tclsh`` is looked for in the Tcl installation + designated by :instopt:`--with-tcl` if this option is set, then in standard + binary paths. Set this option to decouple the interpreter shell running the + installed scripts from the Tcl installation the extension library is built + against. + .. only:: html or latex .. versionadded:: 4.0 + .. versionchanged:: 5.8 + Default interpreter shell is looked for in the Tcl installation + designated by :instopt:`--with-tcl` + .. instopt:: --with-tcl-linter=BIN Name or full path of program to use to lint modulefile through the diff --git a/NEWS.rst b/NEWS.rst index f3c5180ad..7045c54b1 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -6,6 +6,17 @@ Release notes This file describes changes in recent versions of Modules. It primarily documents those changes that are of interest to users and admins. +.. _5.8 release notes: + +Modules 5.8.0 (not yet released) +-------------------------------- + +* Install: look for the Tcl interpreter shell in the Tcl installation + designated by :instopt:`--with-tcl` when :instopt:`--with-tclsh` is not set, + so that installed scripts run with the same Tcl the extension library is + built against. (fix issue #717) + + .. _5.7 release notes: Modules 5.7.0 (2026-09-21) diff --git a/configure b/configure index dc3d858b2..ab465f834 100755 --- a/configure +++ b/configure @@ -88,6 +88,7 @@ pathentryreorder=n loadedmodules= quarantinevars= binsearchpath=/usr/bin:/bin:/usr/local/bin +tcldir= TCLSH=tclsh PYTHON=python SPHINXBUILD=sphinx-build @@ -522,13 +523,16 @@ Optional Packages: TAGLIST is a tag name or abbreviation (elements in TAGLIST are separated by \`:') [$tagcolorname] --with-tcl directory containing the Tcl configuration script - tclConfig.sh. + tclConfig.sh. Tcl interpreter shell is also looked + for in this Tcl installation (see --with-tclsh). --with-tcl-linter=BIN name of full path of program to use to lint Tcl modulefiles [$tcllinter] --with-tcl-linter-opts=OPTLIST settings to apply to tcl linter program [$tcllinteropts] --with-tclinclude directory containing the Tcl header files. - --with-tclsh=BIN name or full path of Tcl interpreter shell [tclsh] + --with-tclsh=BIN name or full path of Tcl interpreter shell. Unless + set, tclsh is looked for in the Tcl installation + designated by --with-tcl then in PATH [tclsh] --with-terminal-background=VALUE terminal background color which determines the color set to apply by default between the \`dark' background @@ -611,6 +615,13 @@ check_requirement() { fi } +# get value of a variable defined in Tcl configuration script +get_tclconfig_value() { + # source script in a subshell to keep its variables out of our environment + # shellcheck disable=SC1090 + (. "$1" >/dev/null 2>&1; echo "${!2}") +} + # parse optional argument to find if feature is enabled or disabled get_feature_value() { typeset val="${1#*=}" @@ -986,7 +997,10 @@ for arg in "$@"; do --with-tcl-linter-opts=*|--without-tcl-linter-opts) # shellcheck disable=SC2034 tcllinteropts=$(get_package_value "$arg" "") ;; - --with-tcl=*|--without-tcl|--with-tclinclude=*|--without-tclinclude) + --with-tcl=*|--without-tcl) + tcldir=$(get_package_value "$arg") + libarglist+=("$arg") ;; + --with-tclinclude=*|--without-tclinclude) libarglist+=("$arg") ;; --with-python=*|--without-python) pythonbin=$(get_package_value "$arg") ;; @@ -1112,8 +1126,46 @@ fi if [ -n "$tclshbin" ]; then check_requirement "$tclshbin" '' "PATH=$binsearchpath" else - # also check version-specific names in case no generic tclsh binary exists - check_requirement $TCLSH '' "PATH=$binsearchpath" 'tclsh8.6' 'tclsh8.5' 'tclsh8.4' + reqpath='' + # look first in the Tcl installation designated by --with-tcl, so that + # installed scripts run with the Tcl the extension library is built + # against rather than with whatever tclsh comes first in PATH + if [ -n "$tcldir" ]; then + # accept tclConfig.sh file path like extension library configure does + tcldir=${tcldir%/tclConfig.sh} + # the configuration script records where Tcl binaries are installed and + # the version suffix of the interpreter shell + if [ -f "$tcldir/tclConfig.sh" ]; then + tclexecprefix=$(get_tclconfig_value "$tcldir/tclConfig.sh" \ + TCL_EXEC_PREFIX) + tclversion=$(get_tclconfig_value "$tcldir/tclConfig.sh" TCL_VERSION) + else + tclexecprefix='' + tclversion='' + fi + if [ -n "$tclexecprefix" ]; then + tclbinsearchpath="$tclexecprefix/bin" + else + # assume tclConfig.sh lies in a lib directory sibling to bin + tclbinsearchpath=$(cd "$tcldir/../bin" 2>/dev/null && pwd \ + || echo "$tcldir/../bin") + fi + if [ -n "$tclversion" ]; then + check_requirement "tclsh$tclversion" '-' "PATH=$tclbinsearchpath" \ + 'tclsh' + else + check_requirement 'tclsh' '-' "PATH=$tclbinsearchpath" 'tclsh9.0' \ + 'tclsh8.6' 'tclsh8.5' + fi + if [ -z "$reqpath" ]; then + echo_warning "No Tcl interpreter shell found in \`$tclbinsearchpath' \ +from Tcl installation designated by \`--with-tcl', looking in standard PATHs" + fi + fi + if [ -z "$reqpath" ]; then + # also check version-specific names in case no generic tclsh binary exists + check_requirement $TCLSH '' "PATH=$binsearchpath" 'tclsh9.0' 'tclsh8.6' 'tclsh8.5' + fi fi TCLSH=$reqpath