Version 7 of Example of a Tcl extension in Swift

Updated 2016-09-21 20:16:43 by dbohdan

dbohdan 2016-09-21: The following is an example of how to implement a simple Tcl extension in Swift 3.0 under Linux. Note the use of @_cdecl: when Tcl loads foo.so it looks for the symbol Foo_Init in it but since Swift mangles names you can't simply write func Foo_Init ... and be done with it. Annotating the function with @_cdecl("Foo_Init") exposes it under the symbol name Foo_Init to C code like the Tcl interpreter.

This code has been tested with Apple's official Swift 3.0-RELEASE on Ubuntu 14.04. You can install Swift by following these instructions . If you copy and paste the makefile from the wiki be sure to replace the leading spaces with tabs with the command sed -i 's| |\t|' Makefile.

Makefile

TARGET ?= libtclswiftexample.so

test: $(TARGET) bridge.h
        echo 'load $(TARGET); puts [hello]; puts [square 5]' | tclsh
$(TARGET): example.swift
        swiftc -emit-library -import-objc-header bridge.h $< -o $(TARGET)
clean:
        -rm $(TARGET)
.PHONY: clean test

bridge.h

#include "/usr/include/tcl/tcl.h"

example.swift

func Hello_Cmd(cdata: ClientData?,
                      interp: UnsafeMutablePointer<Tcl_Interp>?,
                      objc: Int32,
                      objv: UnsafePointer<UnsafeMutablePointer<Tcl_Obj>?>?) -> Int32 {
    if objc != 1 {
        return TCL_ERROR
    }
    Tcl_SetObjResult(interp, Tcl_NewStringObj("Hello, World!", -1))
    return TCL_OK
}

func Square_Cmd(cdata: ClientData?,
                       interp: UnsafeMutablePointer<Tcl_Interp>?,
                       objc: Int32,
                       objv: UnsafePointer<UnsafeMutablePointer<Tcl_Obj>?>?) -> Int32 {
    if objc != 2 {
        return TCL_ERROR
    }
    var i: Int32 = 0
    if Tcl_GetIntFromObj(interp, objv![1], &i) != TCL_OK {
        return TCL_ERROR
    }
    Tcl_SetObjResult(interp, Tcl_NewIntObj(i*i))
    return TCL_OK
}

@_cdecl("Tclswiftexample_Init")
public func Tclswiftexample_Init(interp: UnsafeMutablePointer<Tcl_Interp>) -> CInt {
    Tcl_CreateObjCommand(interp, "::hello", Hello_Cmd, nil, nil);
    Tcl_CreateObjCommand(interp, "::square", Square_Cmd, nil, nil);
    return TCL_OK
}