Skip to content

gh-150836: Mount embedded Tk ZIP in _tkinter on Windows#151562

Open
jjhelmus wants to merge 3 commits into
python:mainfrom
jjhelmus:jjh/mount_tk_dll
Open

gh-150836: Mount embedded Tk ZIP in _tkinter on Windows#151562
jjhelmus wants to merge 3 commits into
python:mainfrom
jjhelmus:jjh/mount_tk_dll

Conversation

@jjhelmus

@jjhelmus jjhelmus commented Jun 16, 2026

Copy link
Copy Markdown

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.

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.
Comment thread Modules/_tkinter.c Outdated
wchar_t tk_path[MAX_PATH];
DWORD path_len = GetModuleFileNameW(tk_module, tk_path, MAX_PATH);

if (path_len == 0 || path_len >= MAX_PATH) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assume MAX_PATH, unfortunately, since it's quite likely that Python could be running in a long path. At a minimum, use 512 instead (which is what is used in dynload_win.c for importing native modules), or we have to do a loop that increases (doubles) the buffer size until path_len < buffer_len.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it can be done with Tcl's APIs, go for it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjust the logic here to loop until a long enough buffer is found using the pattern in Modules/getpath.c:winmodule_to_dict

Comment thread Modules/_tkinter.c
Tcl_DStringInit(&utf8_path);
Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path);
(void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path),
"//zipfs:/lib/tk", NULL);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this handles re-mounting without an issue? It seems like it could be called multiple times by someone's code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling TclZipfs_Mount on an existing mount leaves the original untouched but does raise an error. Since this call passes a null interpreter this error is discarded. Trying to mount a DLL without an embedded Zip also results in a discarded error.
I added a comment about the failures here being harmless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants