This tutorial explains how to set up the Xcode project for writing a Marta plugin in Swift. The content is very similar to the Objective-C Interoperability tutorial, and I will refer to relevant sections of it. Yet, there are a few significant differences, and I want to cover them here.
Setting up the project
Project configuration is exactly the same as in the Objective-C tutorial. Please follow the steps described there, but set the product name to swiftinterop
.
We do not need the Objective-C files Xcode created for us, and you can move swiftinterop.h
and swiftinterop.m
to Trash. Instead, create a plugin.swift
(right-click on the swiftinterop
folder, “New File…” → “Swift File” → “Next” → plugin.swift
→ “Create”).
Xcode will suggest you configure an Objective-C bridging header. We will need it, so click on “Create Bridging Header”.
Swift part
Swift cannot import C headers directly. To call Lua C API, we need to add an import to the bridging header.
Open swiftinterop-Bridging-Header.h
and add the following import directive:
#import "lauxlib.h"
Now we can add an entry point, together with our helloWorld()
function.
And here is plugin.swift
:
import Cocoa
private let helloWorld: lua_CFunction = { L in
let alert = NSAlert()
alert.messageText = "Hello from Swift!"
alert.runModal()
}
@_cdecl("luaopen_libswiftinterop")
public func luaopen_libswiftinterop(L: OpaquePointer) -> CInt {
let library: [(String, lua_CFunction)] = [
("helloWorld", helloWorld)
]
lua_createtable(L, 0, Int32(library.count))
for (name, function) in library {
lua_pushcclosure(L, function, 0)
lua_setfield(L, -2, name)
}
return 1
}
As you have probably noticed, there are some differences, comparing to C and Objective-C:
- First of all, Swift does not understand function-like macros such as
luaL_newlib()
. So we initialize the library manually by creating a table and filling it with functions we want to expose. - Also, Swift cannot reference opaque structures, so we get an
OpaquePointer
instead oflua_State*
. - Finally, we used the
@_cdecl
attribute, which exposes the function to C.
We implemented helloWorld()
as a closure, yet it is not required. Instead, you can declare an ordinary function:
private func helloWorld(L: OpaquePointer!) -> CInt {
let alert = NSAlert()
alert.messageText = "Hello from Swift!"
alert.runModal()
return 0
}
That’s it! You can build the library the same way as explained in the Objective-C Interoperability tutorial.
Lua part
The Lua part is also the same:
marta.expose()
plugin {
id = "marta.example.swiftinterop",
name = "Swift Interoperability Test",
apiVersion = "2.1"
}
local interop = require "libswiftinterop"
action {
id = "test",
name = "Test Swift Interoperability",
apply = function(context)
interop.helloWorld()
end
}
After a restart, you should be able to run the “Test Swift Interoperability” test.