GeezerVison is showing github.com — Tkinter fails to build with Tcl 9.0 due to `Tcl_AppInit()` undeclared · Issue #104363 · python/cpython
Tkinter fails to build with Tcl 9.0 due to Tcl_AppInit() undeclared #104363DescriptionSince Tcl 8.0.5 (tcltk/tcl@17481a9), tcl.h has clarified that Tcl_AppInit() is not an exported Tcl library function, and declares Tcl_AppInit() for compatibility/convenience only:
/*
*----------------------------------------------------------------------------
* Convenience declaration of Tcl_AppInit for backwards compatibility. This
* function is not *implemented* by the tcl library, so the storage class is
* neither DLLEXPORT nor DLLIMPORT.
*/
extern Tcl_AppInitProc Tcl_AppInit;
This declaration is deprecated in Tcl 8.7 and removed in Tcl 9.0. Without it, _tkinter.c will fail to build if the compiler treats implicit function declarations as errors:
./Modules/_tkinter.c:713:9: error: call to undeclared function 'Tcl_AppInit'; ISO C99 and later do not support implicit function declarations [-Werror,-Wimplicit-function-declaration]
if (Tcl_AppInit(v->interp) != TCL_OK) {
^
./Modules/_tkinter.c:713:9: note: did you mean 'Tcl_Init'?
/Users/user/tcl90p/include/tclDecls.h:513:13: note: 'Tcl_Init' declared here
EXTERN int Tcl_Init(Tcl_Interp *interp);
^
Although it seems possible to have _tkinter.c declare Tcl_AppInit() when tcl.h does not, I am not familiar enough with Tcl_AppInit() usage to know whether that is a good solution. From reading the Tcl_AppInit() documentation, it sounds like Tkinter could instead rename its Tcl_AppInit() in tkappinit.c to something else, which it then always declares in _tkinter.c. Activityterryjreedy commented on May 30, 2023 serhiy-storchaka commented on Jun 4, 2024 I agree with the analysis of @chrstphrchvz. I came to the same two possible quick solutions, and I also not qualified to decide what is better.
For now, it looks safer to add the missing declaration of Tcl_AppInit:
#if TK_MAJOR_VERSION >= 9
int Tcl_AppInit(Tcl_Interp *);
#endif
If the user code uses an embedded Python or a custom build of Python with statically linked Tcl/Tk and third-party binary Tcl/Tk libraries, they will still be able to define a custom Tcl_AppInit().
In future we may implement more modern approach, but this minimum is necessary to build Tkinter with Tcl/Tk 9.0.
I'll add this change in #112681 because both changes are needed to unblock a build. serhiy-storchaka commented on Jun 4, 2024 Tkinter builds now with Tcl 9.0. I leave this issue open for the case if we find better solution. Reacted by Data Scientist 89 dkfellows commented on Mar 20, 2025 It shouldn't be necessary to call at all; it's there for tclsh itself and Tcl only calls it from Tcl_Main (which tkinter definitely shouldn't use, as it is a never-return function!)
Cutting out bits that ought to be ignorable, in Tcl 9.0 it's just (on POSIX; Windows has a different RC file name):
int Tcl_AppInit(Tcl_Interp *interp) {
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
(void) Tcl_EvalEx(interp,
"set tcl_rcFileName [file tildeexpand ~/.tclshrc]",
-1, TCL_EVAL_GLOBAL);
return TCL_OK;
}
The setting of tcl_rcFileName is only relevant if you're running interactively, which I'm fairly sure is not a good idea for you either. Which means you can just replace the call to Tcl_AppInit with a call to Tcl_Init, which is exported. serhiy-storchaka commented on Jun 27, 2026 The build failure itself was fixed in #112681 (gh-112681) by adding the missing declaration under #if TK_MAJOR_VERSION >= 9, and Tkinter has built against Tcl/Tk 9.0/9.1 since. I left this open in case a cleaner approach emerged, but on review the minimal declaration is the right one.
The tempting alternative — rename our Tcl_AppInit to a private name and drop the version guard — would break a documented customization seam. configure sets -DWITH_APPINIT=1 on every standard build, so the live Tcl_AppInit is the one in Modules/tkappinit.c, which is the hook for statically linking Tcl/Tk packages (-DWITH_TIX/WITH_BLT/WITH_TOGL/…). Renaming it silently breaks anyone patching that file.
@dkfellows is right that the name isn't special (Tcl only calls it from Tcl_Main, which we don't use) — which is exactly why declaring and calling our own is fine. And we can't reduce the call to a bare Tcl_Init, since our Tcl_AppInit also handles _tkinter_skip_tk_init and Tkinter_TkInit.
So closing as completed. Retiring tkappinit.c/WITH_APPINIT altogether (Tix is gone in Tcl 9; BLT/Togl/static-PIL are long dead) is worth considering, but that's a separate cleanup.
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|