From 08a23a13b0edd8f19452b377358b5c6049b773a2 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Wed, 8 Oct 2025 22:25:14 +0300 Subject: [PATCH 1/9] Support buiding against Tcl/Tk 9 Tct/Tk 9 changes the name of the Tk library Use tkConfig.sh for future-proofing --- plugins/python-build/bin/python-build | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index 3c1e6ea4..a1fecf2b 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1887,19 +1887,12 @@ use_homebrew_tcltk() { for tcltk in ${PYTHON_BUILD_TCLTK_FORMULA:-tcl-tk@8 tcl-tk}; do local tcltk_libdir="$(brew --prefix "${tcltk}" 2>/dev/null || true)" if [ -d "$tcltk_libdir" ]; then - echo "python-build: use tcl-tk from homebrew" - local tcltk_version="$(sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo $TCL_VERSION')" - local tcltk_includes tcltk_libs + echo "python-build: use ${PYTHON_BUILD_TCLTK_FORMULA} from homebrew" # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir. - # We're not using tclConfig.sh here 'cuz it produces the version-specific path to /Cellar - # and we'd rather have rpath set to /opt/<...> to allow micro release upgrades without rebuilding - # XXX: do use tclConfig.sh and translate the paths if more shenanigans appear in later releases - if [ -d "$tcltk_libdir/include/tcl-tk" ]; then - tcltk_includes="-I$tcltk_libdir/include/tcl-tk" - else - tcltk_includes="-I$tcltk_libdir/include" - fi - tcltk_libs="-L$tcltk_libdir/lib -ltcl$tcltk_version -ltk$tcltk_version" + local tcltk_includes="$(sh -c '. '"$tcltk_libdir"'/lib/tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" + # Tcl/Tk is not keg-only so it's safe to use -L with Cellar path; rpath would be of Homebrew + # and would not break with version upgrades + local tcltk_libs="$(sh -c '. '"$tcltk_libdir"'/lib/tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" # Since 2.7.6, 3.3.3, 3.4.0 (Issue #1584): --with-tcltk-includes + --with-tcltk-libs Configure options # Since 3.11.0 (bpo-45847): `pkg-config` call, TCLTK_CFLAGS + TCLTK_LIBS override if [[ -n "$PYTHON_BUILD_TCLTK_USE_PKGCONFIG" ]]; then From 7ea55b784a97891b81b5d874ca371add34ae20e1 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Wed, 8 Oct 2025 23:40:55 +0300 Subject: [PATCH 2/9] fix specs --- plugins/python-build/bin/python-build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index a1fecf2b..e77d29fd 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1889,10 +1889,10 @@ use_homebrew_tcltk() { if [ -d "$tcltk_libdir" ]; then echo "python-build: use ${PYTHON_BUILD_TCLTK_FORMULA} from homebrew" # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir. - local tcltk_includes="$(sh -c '. '"$tcltk_libdir"'/lib/tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" + local tcltk_includes="$(sh -c 'cd "$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" # Tcl/Tk is not keg-only so it's safe to use -L with Cellar path; rpath would be of Homebrew # and would not break with version upgrades - local tcltk_libs="$(sh -c '. '"$tcltk_libdir"'/lib/tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" + local tcltk_libs="$(sh -c 'cd "$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" # Since 2.7.6, 3.3.3, 3.4.0 (Issue #1584): --with-tcltk-includes + --with-tcltk-libs Configure options # Since 3.11.0 (bpo-45847): `pkg-config` call, TCLTK_CFLAGS + TCLTK_LIBS override if [[ -n "$PYTHON_BUILD_TCLTK_USE_PKGCONFIG" ]]; then From a887bb0c3d82364155bf0856efc78f49155d8ae2 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Wed, 8 Oct 2025 23:42:05 +0300 Subject: [PATCH 3/9] fix --- plugins/python-build/bin/python-build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index e77d29fd..fc59122e 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1889,10 +1889,10 @@ use_homebrew_tcltk() { if [ -d "$tcltk_libdir" ]; then echo "python-build: use ${PYTHON_BUILD_TCLTK_FORMULA} from homebrew" # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir. - local tcltk_includes="$(sh -c 'cd "$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" + local tcltk_includes="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" # Tcl/Tk is not keg-only so it's safe to use -L with Cellar path; rpath would be of Homebrew # and would not break with version upgrades - local tcltk_libs="$(sh -c 'cd "$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" + local tcltk_libs="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" # Since 2.7.6, 3.3.3, 3.4.0 (Issue #1584): --with-tcltk-includes + --with-tcltk-libs Configure options # Since 3.11.0 (bpo-45847): `pkg-config` call, TCLTK_CFLAGS + TCLTK_LIBS override if [[ -n "$PYTHON_BUILD_TCLTK_USE_PKGCONFIG" ]]; then From 337c7096c76338db1184b464bca080971fcdd341 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Thu, 9 Oct 2025 09:09:43 +0300 Subject: [PATCH 4/9] support tcl with external libtommath --- plugins/python-build/bin/python-build | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index fc59122e..07cf8b1d 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1880,18 +1880,23 @@ use_macports_zlib() { use_homebrew_tcltk() { can_use_homebrew || return 1 - # Since https://github.com/Homebrew/homebrew-core/commit/f10e88617b41555193c22fdcba6109fe82155ee2 (10.11.2024), - # tcl-tk is 9.0 which is not compatible with CPython as of this writing - # but we'll keep it as backup for cases like non-updated Homebrew local tcltk + # Since https://github.com/Homebrew/homebrew-core/commit/f10e88617b41555193c22fdcba6109fe82155ee2 (10.11.2024), + # tcl-tk is 9.0. It's supported in CPython since 3.14.0a1 (gh-124111) but is not officially supported as of 3.14.0 + # so we prefer 8 for tcltk in ${PYTHON_BUILD_TCLTK_FORMULA:-tcl-tk@8 tcl-tk}; do local tcltk_libdir="$(brew --prefix "${tcltk}" 2>/dev/null || true)" if [ -d "$tcltk_libdir" ]; then echo "python-build: use ${PYTHON_BUILD_TCLTK_FORMULA} from homebrew" # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir. local tcltk_includes="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" - # Tcl/Tk is not keg-only so it's safe to use -L with Cellar path; rpath would be of Homebrew - # and would not break with version upgrades + # Homebrew Tcl/Tk 9 is built with external libtommath. CPython's build as of 3.14.0 does not detect that and fails to link to tommath symbols + local tcltk_cflags + if sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo "$TCL_DEFS"' | grep -qwf '-DTCL_WITH_EXTERNAL_TOMMATH=1'; then + tcltk_cflags="${tcltk_includes} -DTCL_WITH_EXTERNAL_TOMMATH=1" + fi + # For some reason, keg-only tcl-tk@8 successfully links with Tkinter without specifying rpath, with `/opt' rpath + # so no need to translate /Cellar path to /opt path local tcltk_libs="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" # Since 2.7.6, 3.3.3, 3.4.0 (Issue #1584): --with-tcltk-includes + --with-tcltk-libs Configure options # Since 3.11.0 (bpo-45847): `pkg-config` call, TCLTK_CFLAGS + TCLTK_LIBS override @@ -1900,11 +1905,12 @@ use_homebrew_tcltk() { # There's no way to provide a fallback only if it's is not present # and Configure's logic of detecting if it's present is complicated. # So we just override it always - export TCLTK_CFLAGS="$tcltk_includes" + export TCLTK_CFLAGS="$tcltk_includes${tcltk_cflags:+ $tcltk_cflags}" export TCLTK_LIBS="$tcltk_libs" else package_option python configure --with-tcltk-includes="$tcltk_includes" package_option python configure --with-tcltk-libs="$tcltk_libs" + export CFLAGS="${tcltk_cflags}${CFLAGS:+ $CFLAGS}" fi #set in either case as a failsafe export PKG_CONFIG_PATH="${tcltk_libdir}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" From e5694449d24864572bb6ba056934bcc0bde7fd0c Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Thu, 9 Oct 2025 09:11:16 +0300 Subject: [PATCH 5/9] fix --- plugins/python-build/bin/python-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index 07cf8b1d..3d43081d 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1892,7 +1892,7 @@ use_homebrew_tcltk() { local tcltk_includes="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" # Homebrew Tcl/Tk 9 is built with external libtommath. CPython's build as of 3.14.0 does not detect that and fails to link to tommath symbols local tcltk_cflags - if sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo "$TCL_DEFS"' | grep -qwf '-DTCL_WITH_EXTERNAL_TOMMATH=1'; then + if sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo "$TCL_DEFS"' | grep -qwFe '-DTCL_WITH_EXTERNAL_TOMMATH=1'; then tcltk_cflags="${tcltk_includes} -DTCL_WITH_EXTERNAL_TOMMATH=1" fi # For some reason, keg-only tcl-tk@8 successfully links with Tkinter without specifying rpath, with `/opt' rpath From 0e34a588cadf473f0feaef2cc5384dc99f16c379 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Thu, 9 Oct 2025 10:43:40 +0300 Subject: [PATCH 6/9] flags in case of --with-tcl-* --- plugins/python-build/bin/python-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index 3d43081d..e6377b17 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1910,7 +1910,7 @@ use_homebrew_tcltk() { else package_option python configure --with-tcltk-includes="$tcltk_includes" package_option python configure --with-tcltk-libs="$tcltk_libs" - export CFLAGS="${tcltk_cflags}${CFLAGS:+ $CFLAGS}" + [[ -n $tcltk_cflags ]] && export CFLAGS="${tcltk_cflags}${CFLAGS:+ $CFLAGS}" fi #set in either case as a failsafe export PKG_CONFIG_PATH="${tcltk_libdir}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" From cf421c05362d73a399bc4ff88a1cc33ae121fa55 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Thu, 9 Oct 2025 15:12:23 +0300 Subject: [PATCH 7/9] (rename var) --- plugins/python-build/bin/python-build | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/python-build/bin/python-build b/plugins/python-build/bin/python-build index e6377b17..e49fb806 100755 --- a/plugins/python-build/bin/python-build +++ b/plugins/python-build/bin/python-build @@ -1885,19 +1885,19 @@ use_homebrew_tcltk() { # tcl-tk is 9.0. It's supported in CPython since 3.14.0a1 (gh-124111) but is not officially supported as of 3.14.0 # so we prefer 8 for tcltk in ${PYTHON_BUILD_TCLTK_FORMULA:-tcl-tk@8 tcl-tk}; do - local tcltk_libdir="$(brew --prefix "${tcltk}" 2>/dev/null || true)" - if [ -d "$tcltk_libdir" ]; then + local tcltk_prefix="$(brew --prefix "${tcltk}" 2>/dev/null || true)" + if [ -d "$tcltk_prefix" ]; then echo "python-build: use ${PYTHON_BUILD_TCLTK_FORMULA} from homebrew" # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir. - local tcltk_includes="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" + local tcltk_includes="$(sh -c 'cd '"$tcltk_prefix"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_INCLUDE_SPEC $TK_INCLUDE_SPEC"')" # Homebrew Tcl/Tk 9 is built with external libtommath. CPython's build as of 3.14.0 does not detect that and fails to link to tommath symbols local tcltk_cflags - if sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo "$TCL_DEFS"' | grep -qwFe '-DTCL_WITH_EXTERNAL_TOMMATH=1'; then - tcltk_cflags="${tcltk_includes} -DTCL_WITH_EXTERNAL_TOMMATH=1" + if sh -c '. '"$tcltk_prefix"'/lib/tclConfig.sh; echo "$TCL_DEFS"' | grep -qwFe '-DTCL_WITH_EXTERNAL_TOMMATH=1'; then + tcltk_cflags="-DTCL_WITH_EXTERNAL_TOMMATH=1" fi # For some reason, keg-only tcl-tk@8 successfully links with Tkinter without specifying rpath, with `/opt' rpath # so no need to translate /Cellar path to /opt path - local tcltk_libs="$(sh -c 'cd '"$tcltk_libdir"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" + local tcltk_libs="$(sh -c 'cd '"$tcltk_prefix"'/lib; . tclConfig.sh; . tkConfig.sh; echo "$TCL_LIB_SPEC $TK_LIB_SPEC"')" # Since 2.7.6, 3.3.3, 3.4.0 (Issue #1584): --with-tcltk-includes + --with-tcltk-libs Configure options # Since 3.11.0 (bpo-45847): `pkg-config` call, TCLTK_CFLAGS + TCLTK_LIBS override if [[ -n "$PYTHON_BUILD_TCLTK_USE_PKGCONFIG" ]]; then @@ -1913,7 +1913,7 @@ use_homebrew_tcltk() { [[ -n $tcltk_cflags ]] && export CFLAGS="${tcltk_cflags}${CFLAGS:+ $CFLAGS}" fi #set in either case as a failsafe - export PKG_CONFIG_PATH="${tcltk_libdir}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" + export PKG_CONFIG_PATH="${tcltk_prefix}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" lock_in homebrew return 0 From e95f820c436017112b687e9d1cd2a3b158644815 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Thu, 9 Oct 2025 15:12:33 +0300 Subject: [PATCH 8/9] add/adjust tests --- plugins/python-build/test/build.bats | 103 +++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/plugins/python-build/test/build.bats b/plugins/python-build/test/build.bats index d123103e..3797566c 100644 --- a/plugins/python-build/test/build.bats +++ b/plugins/python-build/test/build.bats @@ -68,6 +68,20 @@ assert_build_log() { assert_output } +stub_tcltk() { + tcl_tk_libdir="${1:?}" + mkdir -p "$tcl_tk_libdir/lib" + cat >"$tcl_tk_libdir/lib/tclConfig.sh" <"$tcl_tk_libdir/lib/tkConfig.sh" <>"$tcl_tk_libdir/lib/tclConfig.sh" + stub_tcltk "${tcl_tk_libdir:=BATS_TEST_TMPDIR/homebrew-tcl-tk}" stub uname '-s : echo Darwin' stub sw_vers '-productVersion : echo 1010' @@ -788,7 +799,40 @@ DEF assert_build_log <>"$tcl_tk_libdir/lib/tclConfig.sh" <>"$tcl_tk_libdir/lib/tclConfig.sh" + stub_tcltk "${tcl_tk_libdir:=BATS_TEST_TMPDIR/homebrew-tcl-tk}" stub uname '-s : echo Darwin' stub sw_vers '-productVersion : echo 1010' @@ -822,7 +863,7 @@ DEF assert_build_log <>"$tcl_tk_libdir/lib/tclConfig.sh" + stub_tcltk "${tcl_tk_libdir:=BATS_TEST_TMPDIR/homebrew-tcl-tk}" stub uname '-s : echo Darwin' stub sw_vers '-productVersion : echo 1010' @@ -857,7 +895,42 @@ DEF assert_build_log <>"$tcl_tk_libdir/lib/tclConfig.sh" < Date: Thu, 9 Oct 2025 15:51:57 +0300 Subject: [PATCH 9/9] fix tests --- plugins/python-build/test/build.bats | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/python-build/test/build.bats b/plugins/python-build/test/build.bats index 3797566c..f59c4759 100644 --- a/plugins/python-build/test/build.bats +++ b/plugins/python-build/test/build.bats @@ -69,15 +69,15 @@ assert_build_log() { } stub_tcltk() { - tcl_tk_libdir="${1:?}" - mkdir -p "$tcl_tk_libdir/lib" - cat >"$tcl_tk_libdir/lib/tclConfig.sh" <"$tcltk_prefix/lib/tclConfig.sh" <"$tcl_tk_libdir/lib/tkConfig.sh" <"$tcltk_prefix/lib/tkConfig.sh" <>"$tcl_tk_libdir/lib/tclConfig.sh" <>"$tcl_tk_libdir/lib/tclConfig.sh" <