Author: Ashok P. Nadkarni <[email protected]>
Tcl-Version: 9.1
State: Final
Type: Project
Created: 2026-05-13
Tcl-Branch: tip-755
Forum: 8231468c85
Vote: Done
Vote-Summary: Accepted 6/0/0
Votes-For: AK, AN, HO, KW, JN, MC, SL
Votes-Against: none
Votes-Present: none
Abstract
This TIP proposes a facility to register a callback function to be invoked after initialization of interpreters.
Rationale
The original motivation was support for loading statically linked packages in secondary interpreters (see tickets 4f06d7ca08 and 6094de399d) but is more general purpose.
In 9.0 and earlier, tclsh, wish and similar shells implemented their own
Tcl_AppInit to customize the Tcl interpreter by loading static packages,
adding commands, setting library paths etc.. The registry and dde packages
were loaded using this mechanism in static tclsh and wish builds.
The problem, as reflected in the above bug reports, is that Tcl_AppInit is
only called on the main interpreter so the customization is not present in
secondary interpreters in either the same or other threads.
This TIP addresses this by providing an API to customize all interpreters after their creation.
Further, this facility is also made available to extensions as well as
applications that embed Tcl but do not follow the template for tclsh.
Some possible use cases for this functionality in addition to the above:
Make application-specific "core" commands available in every interpreter by default without requiring a package. For example, a "sqlite-tclsh" that would have the
sqlite3command available in all interpreters by default.Enforce limits on every interpreter using
Tcl_Limit*family of functions,Tcl_SetRecursionLimitetc.Make initialization via
.tclshrctake effect in every interpreter, not just the main one.Constrain all interpreters by removing commands such as
execin cases where safe interpreters may be overkill.Add debugging facilities such as tracing of all commands across all interpreters with
Tcl_CreateTrace.Implement an interpreter registry that allows tracking and discovery of all active interpreters.
Note that while some (not all!) of the above can be implemented already by script level customization, that needs to be done at every call site that creates interpreters which is both inconvenient (requiring potentially complex wrappers) and not always possible in case of interpreters created within extensions.
Specification
The following API is added to the core and exported via the stubs table.
typedef int Tcl_PostInitProc (Tcl_Interp *interp, void *clientData);
int Tcl_RegisterPostInitProc(Tcl_PostInitProc *postInitProc, void *clientData);
int Tcl_UnregisterPostInitProc(Tcl_PostInitProc *postInitProc, void *clientData);
int Tcl_ClearPostInitProcs(void);
An application can call Tcl_RegisterPostInitProc to register a callback,
having the Tcl_PostInitProc signature, that should be invoked after
initialization (via Tcl_Init, not creation via Tcl_CreateInterp) of every
subsequently created interpreter. The function returns a Tcl return code.
The callbacks are invoked at the end of any call to Tcl_Init including
via the interp create command with the exception of safe interpreters.
This callback is passed the newly created interpreter and the opaque
clientData value that was passed at the time of registration. It should return
a Tcl return code.
Multiple callbacks are supported and will be invoked in the order of their registration except that an error return from a callback will skip the remaining registrations.
The Tcl return code from the last callback invoked is returned as the return
value from Tcl_Init.
A callback may be unregistered by calling Tcl_UnregisterPostInitProc and
passing it the same postInitProc and clientData values that were passed to
Tcl_RegisterPostInitProc. The function returns a standard Tcl return code.
It is not an error if there is no matching prior registration.
The Tcl_ClearPostInitProcs function unregisters all currently registered
callbacks.
Safe interpreters
The post-initialization callbacks are not run in safe interpreters. This is a design choice to error on side of caution.
Interpreter creation in callbacks
A Tcl_Init call within a post-initialization callback will return an error.
This is by design since otherwise infinite recursion will result unless the
callback takes appropriate precautions.
Interpreter deletion in callbacks
Deletion of the interpreter within its initialization will documented as prohibited and an error returned if attempted. A memory leak will result but is deemed an acceptible consequence of an illegal action. See the forum thread for a sample session.
Registration changes within callbacks
The Tcl_RegisterPostInitProc and Tcl_UnregisterPostInitProc functions may be
invoked from within a registered callback. However, the change in registration
will not have effect for the interpreter that is being initialized.
Implementation notes
Implementation is in the Tcl tip-755 and Tk tip-755 branches.
Tcl notes
In addition to the implementation of the above functions, the following changes are made to Tcl.
Tcl_Inithas been modified to invoke the post-initialization callback functions as the last step before returning. A snapshot of the callback registrations is taken for iterating without locks being held.Static packages (Dde being the only one in Tcl 9.1) are now initialized through this callback mechanism via
Tcl_FindExecutablerather than only for the main interpreter throughTcl_AppInit.Thread finalization handler is added to release the per-thread cache of callbacks. Process exit handler takes care of freeing the process-wide registrations.
Tk notes
The calls to Registry_Init and Dde_Init in static builds have been removed.
These are really internal to Tcl and are no longer needed.
Testing
tcltest has been modified to make use of this functionality and load its
commands in all interpreters, not just the main one. It was deemed appropriate
as an application that added its own static packages. This change is not
mandated for this TIP and can if reverted if deemed inappropriate.
Additionally, as a result of the above, the existing test load-5.1 has been
intentionally modified. The test does an explicit load of a package into a
secondary interpreter and then verifies it against info load using an exact
match. Now however, because static packages are also loaded into secondary
interpreter, the test has been modified to check that the package is one of the
entries in the list returned by info load.
Discussion
The TIP 755 forum thread is set up for discussion of the TIP. Please submit comments there.
History
- 2026-05-26 Added use cases to Rationale
- 2026-05-15 Added
Tcl_UnregisterPostInitProcandTcl_ClearPostInitProcs - 2026-05-16 Added safe interpreters and recursion in callbacks
- 2026-05-18 Add interpreter deletion within callbacks and section on Tcl changes
Copyright
This document has been placed in the public domain.
