Skip to content

Tkinter fails to build with Tcl 9.0 due to Tcl_AppInit() undeclared #104363

Description

@chrstphrchvz

Since 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.

Activity

  1. terryjreedy commented on May 30, 2023

    @terryjreedy
    Member

    @serhiy-storchaka This issue is about patching _tkinter.

  2. serhiy-storchaka commented on Jun 4, 2024

    @serhiy-storchaka
    Member

    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.

  3. serhiy-storchaka commented on Jun 4, 2024

    @serhiy-storchaka
    Member

    Tkinter builds now with Tcl 9.0. I leave this issue open for the case if we find better solution.

  4. dkfellows commented on Mar 20, 2025

    @dkfellows

    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.

  5. serhiy-storchaka commented on Jun 27, 2026

    @serhiy-storchaka
    Member

    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.

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

Metadata

Metadata

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions