Author: Jan Nijtmans <[email protected]>
State: Draft
Type: Project
Vote: Pending
Created: 22-06-2022
Tcl-Version: 9.0
Keywords: Tcl
Tcl-Branch: tcl8-compat
Abstract
Imagine the situation we want to compile an extensions for both Tcl 8.7 and 9.0. That means, two environments need to be set up, with each of them having it's own 'tcl.h' and 'libtclstub<version>.a'.
This TIP proposes bringing this challenge down to a single environment with can compile the extension for both 8.7 (possibly 8.6 also) and 9.0 (with some additional restrictions).
Specification
First, the stub library 'libtclstub9.0.a' is renamed to 'libtclstub.a', so without version number. Reason: the source code of 'libtclstub9.0.a' is exactly the same as 'libtclstub8.7.a', there is no reason to have a version-number in the filename. Actually 'libtclstub9.0.a' has some more functions, which are not usable in Tcl 8.7, but that is handled by proper if'def'ing in 'tcl.h'. This makes 'libtclstub.a' usable for both Tcl 8.x and 9.0.
The biggest difference between 'tcl.h' in 8.7 and 9.0 is that in Tcl 8.7 many variables have 'int' arguments while in Tcl 9.0 those are 'size_t' arguments. That can be handled in 'tcl.h' as follows:
#if !defined(TCL_MAJOR_VERSION) # define TCL_MAJOR_VERSION 9 #endif #if TCL_MAJOR_VERSION > 8 # define Tcl_Size size_t #else # define Tcl_Size int #endif
All parameters in 'tcl.h', 'tclDecls.h' ... are changed to use 'Tcl_Size' in stead of 'size_t'. This makes 'tcl.h' from 9.0 usable for Tcl 8.7 too with the following additional restrictions:
- Anything what was deprecated in Tcl 8.7 (and so, removed in 9.0) is still not usable in this mode.
- It only works for stub-enabled extensions, not for static linking.
- It only works for extensions using the public API only.
- 'TCL_VERSION' and 'TCL_PATCHLEVEL' are not available for extensions
- No guarantee that the extension will load in Tcl 8.6 too (it will work if no Tcl 8.7-specific API is used in the extension)
Demo
So, how should an extension for Tcl 8.7 be compiled in a Tcl 9.0 environment? The
only thing to be done is add -DTCL_MAJOR_VERSION=8
to the CFLAGS
. Everything
else is exactly the same as compiling for Tcl 9.0.
Example. Let's build 'pkga.dll'. This dll can be compiled as follows (for 64-bit Windows) for loading it in tclsh90:
x86_64-w64-mingw32-gcc -shared -DUSE_TCL_STUBS=1 -o tcl9pkga.dll unix/dltest/pkga.c -ltclstubNow, compile the same dll for use in Tcl 8.6 or 8.7:
x86_64-w64-mingw32-gcc -shared -DUSE_TCL_STUBS=1 -DTCL_MAJOR_VERSION=8 -o pkga.dll unix/dltest/pkga.c -ltclstub
You can try it out:
> tclsh90 $ load ./tcl9pkga.dll $ pkga_eq wrong # args: should be "pkga_eq string1 string2" $ exit > tclsh86 $ load ./pkga.dll $ pkga_eq wrong # args: should be "pkga_eq string1 string2" $ exit > tclsh90 $ load ./pkga.dll interpreter uses an incompatible stubs mechanism $ exit
Implementation
See branch tcl8-compat
win/Makefile is adapted such that the 'registry' and 'dde' dll's are compiled for both Tcl 9.0 and 8.6 (since those 2 dll's fulfill all restrictions mentioned above). And also unix/dltest/Makefile is adapted such that 'pkga', 'pkgb' and 'pkgc' also are compiled for both (8.6 and 9.0) environments.
Compatibility
The proposed change is 100% source and binary compatible with Tcl 9.0, but it also makes the 'tcl.h' header file and the stub library compatible with a subset of Tcl 8.7.
Copyright
This document has been placed in the public domain.