Be welcome to the CRuntimeInTcl (short: CriTcl), a system for embedding and using C code from within
Tcl [http://core.tcl-lang.org/tcl] scripts.
This guide contains notes and actions to take by writers of CriTcl-based packages to make their code
workable for both Tcl 8.6 and 9.
[1] Generally, if there is no interest in moving to Tcl 9, i.e. Tcl 8.[456] are the only supported
runtimes, then just keep using CriTcl3.2.
The remainder of this document can be ignored.
[2] Use CriTcl version 3.3.1 if,andonlyif Tcl 9 support is wanted.
With some work this will then also provide backward compatibility with Tcl 8.6.
[3] Header "tcl.h"
Replace any inclusion of Tcl's public "tcl.h" header file in the package's C code with the
inclusion of CriTcl's new header file "tclpre9compat.h".
This includes "tcl.h" and further provides a set of compatibility definitions which make
supporting both Tcl 8.6 and Tcl 9 in a single code base easier.
The following notes assume that this compatibility layer is in place.
[4] critcl::tcl
Before CriTcl 3.3.1 a single default (8.4) was used for the minimum Tcl version, to be overriden
by an explicit critcl::tcl in the package code.
Now the default is dynamic, based on the runtime version, i.e. packageprovideTcl, CriTcl is run
with/on.
When running on Tcl 9 the new default is version 9, and 8.6 else. Note how this other default was
bumped up from 8.4.
As a consequence it is possible to
[1] Support just Tcl 8.4+, 8.5+, by having an explicit critcl::tcl8.x in the package code.
Rememberhowever, it is better to simply stick with CriTcl3.2 for this.
[2] Support just Tcl 9 by having an explicit critcl::tcl9 in the package code.
[3] Support both Tcl 8.6 and Tcl 9 (but not 8.4/8.5) by leaving critcl::tcl out of the code and
using the proper tclsh version to run CriTcl with.
[5] Code checking
CriTcl 3.3.1 comes with a very basic set of code checks pointing out places where compatibility
might or will be an issue.
The implementation checks all inlined C code declared by critcl::ccode, critcl::ccommand,
critcl::cproc (and related/derived commands), as well as the C companion files declared with
critcl::csources.
It is very basic because it simply greps the code line by line for a number of patterns and
reports on their presence. The C code is not fully parsed. The check can and will report pattern
found in C code comments, for example.
The main patterns deal with functions affected by the change to Tcl_Size, the removal of old-style
interpreter state handling, and command creation.
A warning message is printed for all detections.
This is disabled for the Tcl_Size-related pattern if the line also matches the pattern *OKtcl9*.
In this way all places in the code already handled can be marked and excluded from the warnings.
[1] Interpreter State handling
Tcl 9 removed the type Tcl_SavedResult and its associated functions Tcl_SaveResult,
Tcl_RestoreResult, and Tcl_DiscardResult.
When a package uses this type and the related functions a rewrite is necessary.
With Tcl 9 use of type Tcl_InterpState and its functions Tcl_SaveInterpState,
Tcl_RestoreInterpState, and Tcl_DiscardInterpState is now required.
As these were introduced with Tcl 8.5 the rewrite gives us compatibility with Tcl 8.6 for
free.
[2] Tcl_Size
One of the main changes introduced with Tcl 9 is the breaking of the 2G barrier for the
number of bytes in a string, elements in a list, etc. In a lot of interfaces int was
replaced with Tcl_Size, which is effectively ptrdiff_t behind the scenes.
The "tclpre9compat.h" header mentioned above provides a suitable definition of Tcl_Size for
8.6, i.e. maps it to int. This enables the package code to use Tcl_Size everywhere and
still have it work for both Tcl 8.6 and 9.
It is of course necessary to rewrite the package code to use Tcl_Size.
The checker reports all lines in the C code using a function whose signature was changed to
use Tcl_Size over int.
Note that it is necessary to manually check the package code for places where a %d text
formatting specification should be replaced with TCL_SIZE_FMT.
I.e. all places where Tcl_Size values are formatted with printf-style functions a
formatting string
"... %d ..."
has
"... " TCL_SIZE_FMT " ..."
The macro TCL_SIZE_FMT is defined by Critcl's compatibility layer, as an extension of the
TCL_SIZE_MODIFIER macro which only contains the formatting modifier to insert into a plain %d to
handle Tcl_Size values.
Note how the original formatting string is split into multiple strings. The C compiler will fuse
these back together into a single string.
[3] Command creation.
This is technically a part of the Tcl_Size changes.
All places using Tcl_CreateObjCommand have to be rewritten to use Tcl_CreateObjCommand2
instead, and the registered command functions to use Tcl_Size for their objc argument.
The "tclpre9compat.h" header maps this back to the old function when compilation is done
against Tcl 8.6.
CriTcl does this itself for the commands created via critcl::ccommand, critcl::cproc, and
derived places (critcl::class).
[4] TIP 494. This TIP adds three semantic constants wrapping -1 to Tcl 9 to make the meaning of
code clearer. As part of this it also casts the constant to the proper type. They are:
• TCL_IO_FAILURE
• TCL_AUTO_LENGTH
• TCL_INDEX_NONE
Critcl's compatibility layer provides the same constants to Tcl 8.6.
Critcl's new checker highlights places where TCL_AUTO_LENGTH is suitable.
Doing this for the other two constants looks to require deeper and proper parsing of C code, which
the checker does not do.