python / cpython

The Python programming language
https://www.python.org/
Other
60.75k stars 29.32k forks source link

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

Open chrstphrchvz opened 1 year ago

chrstphrchvz commented 1 year ago

Since Tcl 8.0.5 (https://github.com/tcltk/tcl/commit/17481a9360ea758b106cce6d9ec42c575a877eb5), 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.

terryjreedy commented 1 year ago

@serhiy-storchaka This issue is about patching _tkinter.

serhiy-storchaka commented 3 weeks ago

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 3 weeks ago

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