概要
前回はCからSwiftの関数を呼び出してみる方法を書いたけど、swift.h
というヘッダを別に用意する必要があって面倒だし1、@_silgen_name("...")
というattributeもなんだか怪しげな匂いがするし、…というわけで、Swiftの関数やクロージャをC言語の関数ポインタとして処理するという方法もあるので書いてみる。
要約
-
@convention(c)
を使う。 - 以上(これだけで解った貴方はこの記事を読む必要はありません)
環境
- OS X = OS X El Capitan + Xcode 7.3 (Swift 2.2)
- Linux = CentOS 7 + Swift 2.2.1
OS X
$ clang --version
Apple LLVM version 7.3.0 (clang-703.0.29)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ swift --version
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
Target: x86_64-apple-macosx10.9
Linux
$ clang --version
clang version 3.8.0 (tags/RELEASE_380/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
$ swift --version
Swift version 2.2.1 (swift-2.2.1-RELEASE)
Target: x86_64-unknown-linux-gnu
ソースファイル
前々回と同様、ファイルは3つだけ。
$ ls
c.c c.h swift.swift
c.h
#include <unistd.h>
void call_me_later(void (*closure)(), unsigned int seconds);
c.c
#include "c.h"
void call_me_later(void (*closure)(), unsigned int seconds) {
sleep(seconds);
closure();
}
swift.swift
func swift_function() {
print("I just woke up! Yes, I'm Function.")
}
let swift_closure:@convention(c) ()->() = {
print("I just woke up! Uh-oh, I'm Closure.")
}
call_me_later(swift_function, 0)
call_me_later(swift_closure, 2)
※関数であれば@convention(c)
すら要らない。
コンパイル手順
C言語ソースからオブジェクトファイルを作成
OS X, Linux共通
$ clang -c c.c -oc.o
$ ls
c.c c.h c.o swift.swift
オブジェクトファイルと一緒にSwiftソースをコンパイル
OS X
$ xcrun --sdk macosx swiftc swift.swift c.o -import-objc-header c.h
ld: warning: object file (c.o) was built for newer OSX version (10.11) than being linked (10.9)
$ ls
c.c c.h c.o main swift.swift
$ ./main
I just woke up! Yes, I'm Funtion.
I just woke up! Uh-oh, I'm Closure.
Linux
$ swiftc swift.swift c.o -import-objc-header c.h
$ ls
c.c c.h c.o main swift.swift
$ ./main
I just woke up! Yes, I'm Funtion.
I just woke up! Uh-oh, I'm Closure.
できた。これでおわり。
ね、簡単でしょう2?