mike-neckのブログ

Java or Groovy or Swift or Golang

Swift から C の関数を呼び出す(Swift Package Manager 使ってる)

Swift から C の関数を呼び出す方法を Swift-NIO のコードを読みながら試した。

f:id:mike_neck:20180609045321p:plain

プロジェクトの構造は普通の2モジュールあるプロジェクト

.
├── Package.swift
├── Sources
│   ├── CExp
│   │   ├── include
│   │   │   └── c_exp.h
│   │   └── shim.c
│   └── SwiftClangCompat
│       └── main.swift
└── Tests
    ├── LinuxMain.swift
    └── SwiftClangCompatTests
         ├── SwiftClangCompatTests.swift
         └── XCTestManifests.swift

CExp は C 言語の関数を呼び出すモジュールで、次のような関数を定義している

c_exp.h
#ifndef C_EXP_H
#define C_EXP_H

#include <stdio.h>

void POSIX_print(char *string);

#endif

実装はただ単に printf を呼び出すだけ

shim.c
#include <c_exp.h>
#include <stdio.h>

void POSIX_print(char *string) {
    printf("%s\n", string);
}

このモジュールを swift のモジュールが参照できるように、 Package.swift を調整する。

// swift-tools-version:4.2

import PackageDescription

let package = Package(
    name: "SwiftClangCompat",
    dependencies: [],
    targets: [
        .target(name: "CExp", dependencies: []),
        .target(name: "SwiftClangCompat", dependencies: ["CExp"]),
        .testTarget(name: "SwiftClangCompatTests", dependencies: ["SwiftClangCompat"]),
    ]
)

そのうえで、Swift 側で C のモジュールを import して呼び出す。

import Foundation
import CExp

let string = "(☝՞ਊ ՞)☝ウェーイwww "

string.withCString { (strPtr: UnsafePointer<Int8>) -> Void in POSIX_print(UnsafeMutablePointer(mutating: strPtr)) }

呼び出し結果

$ swift run SwiftClangCompat
(☝՞ਊ ՞)☝ウェーイwww