[3.15] gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151735)

Tcl/Tk 9 may embed the Tk script library in the Tk DLL on Windows. This embedded library is not found by Tcl by default.

Mount the loaded Tk DLL as a zipfs archive before calling Tk_Init(), so Tk can find its embedded tk_library using its existing library discovery logic.

Preserve Tk_Init()'s normal path if the library is not embedded.
(cherry picked from commit c4eb3adbb4)

Co-authored-by: Jonathan J. Helmus <jjhelmus@gmail.com>
This commit is contained in:
Miss Islington (bot) 2026-06-20 01:31:12 +02:00 committed by GitHub
parent a30acf2495
commit b83a217558
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 61 additions and 3 deletions

View file

@ -0,0 +1 @@
Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows.

View file

@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt.
# include <tk.h>
#endif
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
# include <tkPlatDecls.h>
#endif
#include "tkinter.h"
#if TK_HEX_VERSION < 0x0805020c
@ -175,6 +179,57 @@ _get_tcl_lib_path(void)
}
#endif /* MS_WINDOWS */
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
static void
mount_tk_dll_zip(void)
{
HINSTANCE tk_module = Tk_GetHINSTANCE();
wchar_t *tk_path = NULL;
DWORD path_len = 0;
for (DWORD buffer_len = 256;
tk_path == NULL && buffer_len < (1024 * 1024);
buffer_len *= 2)
{
tk_path = (wchar_t *)PyMem_RawMalloc(
buffer_len * sizeof(*tk_path));
if (tk_path != NULL) {
path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len);
if (path_len == buffer_len) {
PyMem_RawFree(tk_path);
tk_path = NULL;
}
}
}
if (tk_path == NULL || path_len == 0) {
PyMem_RawFree(tk_path);
return;
}
Tcl_DString utf8_path;
Tcl_DStringInit(&utf8_path);
Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path);
/* Failure is harmless if the DLL has no embedded ZIP or if another
interpreter has already mounted it. */
(void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path),
"//zipfs:/lib/tk", NULL);
Tcl_DStringFree(&utf8_path);
PyMem_RawFree(tk_path);
}
#endif
int
Tkinter_TkInit(Tcl_Interp *interp)
{
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
/* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary
does not search. Mount the DLL using Zipfs if possible. */
mount_tk_dll_zip();
#endif
return Tk_Init(interp);
}
/* The threading situation is complicated. Tcl is not thread-safe, except
when configured with --enable-threads.
@ -544,7 +599,7 @@ Tcl_AppInit(Tcl_Interp *interp)
return TCL_OK;
}
if (Tk_Init(interp) == TCL_ERROR) {
if (Tkinter_TkInit(interp) == TCL_ERROR) {
PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
return TCL_ERROR;
}
@ -2988,7 +3043,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
return NULL;
}
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
if (Tk_Init(interp) == TCL_ERROR) {
if (Tkinter_TkInit(interp) == TCL_ERROR) {
Tkinter_Error(self);
return NULL;
}

View file

@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp)
return TCL_OK;
}
if (Tk_Init(interp) == TCL_ERROR) {
if (Tkinter_TkInit(interp) == TCL_ERROR) {
return TCL_ERROR;
}

View file

@ -16,4 +16,6 @@
(TK_RELEASE_LEVEL << 8) | \
(TK_RELEASE_SERIAL << 0))
int Tkinter_TkInit(Tcl_Interp *interp);
#endif /* !TKINTER_H */