概要
- 前回はSwiftからCの関数を呼んだだけだったけど、今回はCからもSwiftの関数を呼んでみる。
要約
- だいたい前回と一緒。
- Swiftの関数はマングリングされてしまうので、Cから呼びたかったら…どっちか:
- Swiftでマングリングを抑止
- CからSwiftのマングリングされた関数を呼び出す
- 今回は1.を採用。理由は次の通り:
- 1.が簡単だから。
- SwiftのABIはまだまだunstableだから1。
環境
前回と同じ。
- 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
ソースファイル
今回は4つファイルを用意してみた。
$ ls
c.c c.h swift.h swift.swift
c.h
#include <stdio.h>
void c_function(const char *string);
void call_swift_function(void);
swift.h
void swift_function(const char *string);
c.c
#include "c.h"
#include "swift.h"
void c_function(const char *string) {
printf("%s", string);
}
void call_swift_function(void) {
swift_function("Hello, I'm C.\n");
}
swift.swift
@_silgen_name("swift_function")
func swift_function(cString:UnsafePointer<CChar>) {
print(String.fromCString(cString)!)
}
c_function("Hello, I'm Swift.\n")
call_swift_function()
※Swift 2.2未満では@_silgen_name
ではなく@asmname
を使いましょう。
コンパイル手順
C言語ソースからオブジェクトファイルを作成
OS X, Linux共通
$ clang -c c.c -oc.o
$ ls
c.c c.h c.o swift.h 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.h swift.swift
$ ./main
Hello, I'm Swift.
Hello, I'm C.
Linux
$ swiftc swift.swift c.o -import-objc-header c.h
$ ls
c.c c.h c.o main swift.h swift.swift
$ ./main
Hello, I'm Swift.
Hello, I'm C.
できた。これでおわり。
ね、簡単でしょう?
そういえば
関数ポインタを受け渡すという手もあるけど、それはまた別の話。