jjno91
jjno91

Reputation: 653

Writing a Tcl extension that will work with multiple versions of Tcl

At my company we are currently using Tcl 8.4 and we are wanting to update to 8.6. The way we want to do this is by writing all of our new C++ extensions to be compatible with 8.6 and 8.4 so that all the new extensions will work on our old testers that we cannot update to 8.4 because of compatibility issues.

Is there a way to write the code or configure VS 2012 so that the dll will detect the version of Tcl and load the libraries it needs dynamically?

If I use the teapot extension architecture will I attain the same result?

Upvotes: 0

Views: 294

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137567

I see from the comments that you already know how to build libraries that use the stub mechanism.

The stubs mechanism is designed to work in such a way that you can use load to bring a DLL into any version of Tcl that is ABI-compatible with the version of Tcl that the DLL was built against. Tcl furthermore has Application Binary Interface compatibility rules that mean that later versions with the same major version number (the “8” in “8.4”) are compatible with earlier versions.

The reverse is not true. 8.4 is not ABI-compatible with 8.6, or at least we don't promise that it is. Even leaving aside the fact that there are additional API functions in 8.6 that aren't in 8.5 or 8.4, the exact slot in the stub table that is used for a particular function may have moved (automatically-generated C macros manage the forward API compatibility, but those don't cope with reverse compatibility). You should always build your extension DLLs against the oldest version of the Tcl API and stub library that you wish to support. (I know of a few people who don't; their code is immensely complex and not at all recommended as an approach.)

However…

That is not the only approach you could take. You could also build the library against each version of Tcl that you wish to support, producing a number of DLLs that you give different names, perhaps mylib84.dll, mylib85.dll and mylib86.dll. Then, you group these together into a Tcl package along with a pkgIndex.tcl that knows how to load the right one, perhaps like this:

if {[package vsatisfies [info tclversion] 8.6]} {
    package ifneeded MyLib 1.0 [list load [file join $dir mylib86.dll]]
} elseif {[package vsatisfies [info tclversion] 8.5]} {
    package ifneeded MyLib 1.0 [list load [file join $dir mylib85.dll]]
} elseif {[package vsatisfies [info tclversion] 8.4]} {
    package ifneeded MyLib 1.0 [list load [file join $dir mylib84.dll]]
}

With this scheme, you can even make the versions for 8.5 and 8.4 be not stub-enabled (if that makes sense in your situation). The only downside is that your build process is now more complex: you have to build three versions of the library instead of one.

By making the code into a package and hiding the details of what is going on within that package, you can do very complex things. For example, variations on this mechanism can be used to build single redistributable packages that support multiple architectures; a single download that supports 32-bit Windows, 64-bit Windows and various versions of Linux, so that you can present a set of straight-forward instructions without lots of platform-dependent bits? You can do it with packages, and the cost is just some build complexity, some bandwidth and some disk space…

Upvotes: 3

Related Questions