Updated 2016-10-02 09:58:39 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.

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.

Note the use of @_cdecl: when Tcl loads the shared library libfoo.so it looks for the symbol Foo_Init in it but since Swift mangles names and has its own calling convention you can't simply write public func Foo_Init ... and have the Tcl interpreter find it. You need to annotate the function with @_cdecl("Foo_Init"), new in Swift 3.0, to expose it to C code under the symbol name Foo_Init with the C calling convention for the platform.

Makefile  edit

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) -ltclstub8.6
clean:
        -rm $(TARGET)
.PHONY: clean test

bridge.h  edit

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

example.swift  edit

func Hello_Cmd(cdata: ClientData?,
               interp: UnsafeMutablePointer<Tcl_Interp>?,
               objc: Int32,
               objv: UnsafePointer<UnsafeMutablePointer<Tcl_Obj>?>?) -> Int32 {
    if objc != 1 {
        Tcl_WrongNumArgs(interp, 1, objv, nil)
        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 {
        Tcl_WrongNumArgs(interp, 1, objv, "value")
        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>) -> Int32 {
    if Tcl_InitStubs(interp, TCL_VERSION, 0) == nil {
        return TCL_ERROR;
    }

    Tcl_CreateObjCommand(interp, "::hello", Hello_Cmd, nil, nil);
    Tcl_CreateObjCommand(interp, "::square", Square_Cmd, nil, nil);
    return TCL_OK
}

See also  edit