I knew that I could work with C libraries directly from Swift, but I've never done it before, so it's a tutorial on libuv uvbook tcp-echo-server I would like to port) to Swift to get started with C language bridges.
This time I will use Xcode on Mac to port tcp-echo-server. The source code is here https://github.com/yokochie/EchoServer-Sample
The Xcode version will be 7.2 and the Swift version will be 2.1.1.
You need libuv to port libuv's tcp-echo-server. Installation is easy with Homebrew.
$ brew install --HEAD libuv
Once installed, the required files will be in / usr / local / {include, lib}.
$ ls /usr/local/include/uv*.h
/usr/local/include/uv-darwin.h /usr/local/include/uv-threadpool.h /usr/local/include/uv-version.h
/usr/local/include/uv-errno.h /usr/local/include/uv-unix.h /usr/local/include/uv.h
$ ls /usr/local/lib/libuv*
/usr/local/lib/libuv.1.dylib /usr/local/lib/libuv.a /usr/local/lib/libuv.dylib
Create a Command Line Tool project by referring to the article Creating a packet monitor with Swift and Libpcap | Developers.IO.
To use libuv, first add libuv.dylib from the project settings and add / usr / local / include /, / usr / local / lib to Header Search Path and Library Search Path of Search Path.
Create Bridging-Header.h somehow (easy to create a new Objective-C file and delete it),
#include <uv.h>
To add.
Then, the libuv method will be suggested as shown in the figure below.
https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift Dare to implement in C language (https://github.com/nikhilm/uvbook/blob/master/code/tcp -I posted something similar to (echo-server / main.c). As shown in the figure at the end of the environment construction, the function can be called as it is, so if the variable types are properly matched, it can be easily ported. I think it will be easier to understand if you compare them while reading this article.
[Using Swift with Cocoa and Objective-C (Swift 2.1): Interacting with C APIs](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/ It will be converted to a type that starts with the acronym C, such as CChar
, CInt
, as described in doc / uid / TP40014216-CH8-ID17). (However, the type suggested on XCode is a type with an explicit number of bits, such as ʻInt8 or ʻInt32
.)
Also, for pointers, Type *
becomes ʻUnsafeMutablePointer and
const Type * becomes ʻUnsafePointer <Type>
. Also, NULL
changes to nil
.
Based on normal type conversion and pointer type conversion
int * hoge = NULL
But
var hoge: UnsafeMutablePointer<CInt> = nil
Will be.
C structure can be used as Swift structure as it is, but if it is a function that requires a variable pointer Is OK if you prefix it with &
(same as if you prefixed the method definition with inout). In this source code, it is done in main.swift: 66.
uv_ip4_addr("0.0.0.0", CInt(DEFAULT_PORT), &addr)
However, this technique doesn't seem to work if casts occur. https://github.com/nikhilm/uvbook/blob/master/code/tcp-echo-server/main.c#L64
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
As it is, with &
, porting did not match the type and a compile error occurred.
Therefore, [withUnsafePointer
function](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/swift/func/s:FSs17withUnsafePointeru0_rFzTRq_FzGVSs13UnsafePointerq_FzGVSs13UnsafePointerq_ I'm casting using the `initializer.
withUnsafePointer(&addr) {
uv_tcp_bind(&server, UnsafePointer<sockaddr>($0), 0)
}
(UnsafePointer Structure Reference does not have anything that can directly take the type of the variable inside the pointer. Please be careful)
Also, although libuv makes heavy use of callback functions, it was possible to specify globally declared functions as they are.
For example, the ʻuv_listenfunction takes
void (* uv_connection_cb) (uv_stream_t * server, int status)at the end of the argument. Https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift#L73 implemented in Swift receives
func on_new_connect (server: UnsafeMutablePointer <uv_stream_t>, status: CInt)` as it is I can pass it.
In C you could use the *
and ->
operators to reference variables in pointers, but in Swift you use the memory
property (https://github.com/yokochie/EchoServer). -Used in Sample / blob / master / EchoServer / main.swift # L13)
Use the ʻUnsafeMutablePointer method to allocate memory and the
destory` method to free it.
It seems that Swift Standard Library does not have a function to output to standard error output, so this time I am issuing an error statement to standard output. It seems that you can do it by opening OutputStream as described in http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/.
Press ⌘R on Xcode to execute. Then in Terminal
$ telnet localhost 7000
To execute. Enter some character such as hoge
and if the same string is displayed, it's OK.
Execution confirmation example
$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hoge
hoge
If you want to build from the command line
$ swiftc main.swift -import-objc-header ../EchoServer-Bridging-Header.h -I/usr/local/include -L/usr/local/lib -luv
If you do, you will have more main
files in the same directory, so you can run it.
Command line tool made with Swift2 --Cookpad developer blog, closure as described in the section "Hooking signal" Can be passed as a function pointer. We have prepared an implementation in https://github.com/yokochie/EchoServer-Sample/blob/use_closure/EchoServer/main.swift instead of a closure.
I think it's almost the same, but the normal closure type is preceded by @convention (c)
. (Hereafter, an example)
let alloc_buffer: @convention(c) (UnsafeMutablePointer<uv_handle_t>, size_t, UnsafeMutablePointer<uv_buf_t>) -> Void = { (handle, suggested_size, buf) in
buf.memory.base = UnsafeMutablePointer<CChar>.alloc(suggested_size)
buf.memory.len = suggested_size
}
For the first time, I touched the C language library from Swift, and I was surprised that it was easier to handle than I expected. Comparing the source code, there are differences in how variables and functions are defined, but I think they are very similar.
I think that Swift is attracting attention as an iOS application implementation language, but I think that it will become more interesting when server programs etc. are implemented in Swift.
This article has become a collection of articles from various people, but I hope more people will try the same thing.
Recommended Posts