はじめに
dynamic framework で C のライブラリを利用したい場合、 Bridging Header 経由では import できないため modulemap を利用します
今回は libevent
を Swift から扱ってみたかったので、それをベースに説明します
modulemap 自体に関する解説はこちらが詳しいです
http://qiita.com/ysn551/items/6f783af2b65c2c4d4631
サンプル
導入
modulemap の定義
module libevent [system] {
link "event"
umbrella header "libevent-umbrella.h"
export *
module * { export * }
}
#import <evhttp.h>
#import <event2/event.h>
#import <event2/http.h>
#import <event2/bufferevent.h>
#import <event2/dns.h>
大雑把に説明すると以下になります
-
module <#モジュール名>
の部分が import する際の名前になる- e.g.
import libevent
- e.g.
-
umbrella header <#ヘッダー名>
の部分でimport
されている宣言が Swift から見えるようになる- Bridging Header と似たようなもの
-
link <#ライブラリ名>
の部分がリンカ処理の際に追加される-
ビルドログなどで目にする
-levent
になる部分 -
場合によってはビルド設定でライブラリの場所を示す
LIBRARY_SEARCH_PATHS
を指示することも必要 -
link
はオプションなので、省略した際は自分でライブラリをリンクする必要がある<img src="https://qiita-image-store.s3.amazonaws.com/0/8508/8525c9c3-4672-d700-bb08-03a1a545e18d.png" width="240px"/>
-
modulemap を Xcode で利用する際はビルド設定の SWIFT_INCLUDE_PATHS
に modulemap が置かれたディレクトリを追加します
ここまで行うと Swift のソースコードで import したライブラリの関数などの補完が働き、実際に実行することができます
利用シーン
import libevent
func http_request_done(req: UnsafeMutablePointer<evhttp_request>, arg: UnsafeMutablePointer<Void>) {
var buf = Array<CChar>(count: 256, repeatedValue: 0)
var nread: Int32 = 0
repeat {
let input = evhttp_request_get_input_buffer(req)
nread = evbuffer_remove(input, &buf, 255)
if nread == 0 { break }
print(String.fromCString(buf))
} while(nread > 0)
event_base_loopbreak(COpaquePointer(arg))
}
var uri_path: String = ""
let uri = evhttp_uri_parse("http://qiita.com/tattsun58/items/50e606696f1daa607a5f")
let host = evhttp_uri_get_host(uri)
let port = evhttp_uri_get_port(uri) == -1 ? 80 : evhttp_uri_get_port(uri)
let path = evhttp_uri_get_path(uri)
if let path = String.fromCString(path) where path.characters.count != 0 {
uri_path = path
} else {
uri_path = "/"
}
let base = event_base_new()
let dns_base = evdns_base_new(base, 1)
let conn = evhttp_connection_base_new(base, dns_base, host, UInt16(port))
let req = evhttp_request_new(http_request_done, UnsafeMutablePointer(base))
evhttp_add_header(req.memory.output_headers, "Host", host)
evhttp_add_header(req.memory.output_headers, "Connection", "close")
evhttp_make_request(conn, req, EVHTTP_REQ_GET, uri_path)
evhttp_connection_set_timeout(req.memory.evcon, 600)
event_base_dispatch(base)
evhttp_connection_free(conn)
event_base_free(base)
おわりに
C ではたくさん出てくる char *
を扱う部分(Swift 上では UnsafePointer<Int8>
)は Swift.String
をそのまま与えることができるので思ったより書きやすかったです
また、今回のサンプルは podspec
を同梱しているので pod install
すれば import libevent
がすぐに利用できるようになっています
※ 事前に brew install libevent
が必要です