Getting started with Swift / C bridges with porting Echo Server using libuv

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.

Environment

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.

installation of libuv

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 an Xcode project

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. LibrarySetting.png SearchPath.png

Allow libuv to be called

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. suggest.png

Getting Started with Swift / C Bridge

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.

About variable types

[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 andconst 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.

Handling of pointers

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 takesvoid (* 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 receivesfunc on_new_connect (server: UnsafeMutablePointer <uv_stream_t>, status: CInt)` as it is I can pass it.

Handling inside the pointer

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 .alloc (size)method to allocate memory and thedestory` method to free it.

Other

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/.

Implementation confirmation

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.

Use closures instead of global functions

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
}

At the end (impression)

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.

References

Recommended Posts

Getting started with Swift / C bridges with porting Echo Server using libuv
Getting Started with Swift
Getting Started with Language Server Protocol with LSP4J
Getting started with Java programs using Visual Studio Code
Getting Started with DBUnit
Use C library with Swift using Clang Modules (modulemap)
Getting Started with Ruby
Getting Started with Docker
Getting Started with Doma-Transactions
Getting Started with Doma-Annotation Processing
Getting Started with Java Collection
Getting Started with JSP & Servlet
Getting Started with Java Basics
Getting Started with Spring Boot
Getting Started with Ruby Modules
Getting Started with Java_Chapter 5_Practice Exercises 5_4
[Google Cloud] Getting Started with Docker
Getting started with Java lambda expressions
Getting Started with Docker with VS Code