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