---
name: "critcl_tcl9"
section: "3tcl"
platform: "linux"
package: "critcl"
version: "3.3.1+dfsg-1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/critcl_tcl9"
---

# critcl\_tcl9(3tcl)

How To Adapt Critcl Packages for Tcl 9

```

```

## NAME

critcl\_tcl9 - How To Adapt Critcl Packages for Tcl 9

## DESCRIPTION

Be welcome to the *C Runtime In Tcl* (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 *CriTcl* **3.2**.

  The remainder of this document can be ignored.

- \[2\]

  Use *CriTcl* version 3.3.1 *if, and only if* 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. **package provide Tcl**, *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::tcl 8.x** in the package code.

    *Remember however*, it is better to simply stick with *CriTcl* **3.2** for this.

  - \[2\]

    Support just Tcl 9 by having an explicit **critcl::tcl 9** 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 **\*OK tcl9\***.

  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.

## ADDITIONAL REFERENCES

- \[1\]

  *https://wiki.tcl-lang.org/page/Porting+extensions+to+Tcl+9*

- \[2\]

  *https://wiki.tcl-lang.org/page/Tcl+9+functions+using+Tcl%5FSize*

- \[3\]

  *https://core.tcl-lang.org/tcl/wiki?name=Migrating%20scripts%20to%20Tcl%209*

- \[4\]

  *https://core.tcl-lang.org/tcl/wiki?name=Migrating%20C%20extensions%20to%20Tcl%209*

## AUTHORS

Jean Claude Wippler, Steve Landers, Andreas Kupries

## BUGS, IDEAS, FEEDBACK

This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report them at *https://github.com/andreas-kupries/critcl/issues*. Ideas for enhancements you may have for either package, application, and/or the documentation are also very welcome and should be reported at *https://github.com/andreas-kupries/critcl/issues* as well.

## KEYWORDS

C code, Embedded C Code, calling C code from Tcl, code generator, compile & run, compiler, dynamic code generation, dynamic compilation, generate package, linker, on demand compilation, on-the-fly compilation

## CATEGORY

Glueing/Embedded C code

## COPYRIGHT

```
Copyright (c) Jean-Claude Wippler
Copyright (c) Steve Landers
Copyright (c) 2011-2024 Andreas Kupries
```
