Rockford Wei,2017-01-17
最近更新:2018-01-23
本程序示范了如何用Swift调用自定义C语言模块的方法。您可以直接下载本程序,或者按照以下教程逐步完成。 此外,示范程序还展示了如何使用 Swift 作为脚本运行,并且在脚本中调用C语言的动态链接库,使得服务器端Swift 开发实现热补丁。
示范程序中有一个C语言的源程序CSwift.c和一个头文件CSwift.h,我们的目标是构造一个CSwift的函数库,能够让swift源程序执行CSwift程序中的函数。
本程序需要Swift 4.0.3 以上版本。
$ git clone https://github.com/RockfordWei/CSwift.git
$ cd CSwift
$ swift build
$ swift test
源程序采用C语言写成,测试程序则是Swift语言编写。因此如果通过测试,则恭喜您,已经成功实现了Swift语言调用C语言的整个过程。
您可以完全不依赖所有上述内容,而一步一步从零开始制作C函数库和调用C库的Swift代码:
仍然假定函数库名称为CSwift。首先找一个空白目录,然后执行:
mkdir CSwift && cd CSwift && swift package init
mkdir Sources/CSwift/include && rm Sources/CSwift/CSwift.swift
上述命令能够新建一个空白的函数库模板
现在编辑头文件 Sources/CSwift/include/Swift.h
:
extern int c_add(int, int);
#define C_TEN 10
然后通过修改文件 Sources/CSwift/CSwift.c
完成函数实现:
#include "include/CSwift.h"
int c_add(int a, int b) { return a + b ; }
下一步为Swift 语言构造一个映射模块文件:
Sources/CSwift/include/module.modulemap
module CSwift [system] {
header "CSwift.h"
export *
}
请修改Tests/CSwiftTests/CSwiftTests.swift文件,内容如下:
import XCTest
@testable import CSwift
class CSwiftTests: XCTestCase {
func testExample() {
// 测试调用 C 函数
let three = c_add(1, 2)
XCTAssertEqual(three, 3)
// 测试调用 C 语言的符号
XCTAssertEqual(C_TEN, 10)
}
static var allTests : [(String, (CSwiftTests) -> () throws -> Void)] {
return [ ("testExample", testExample)]
}
}
最后一步最简单,直接执行:
$ swift build
$ swift test
如果没有问题,那就一切OK了!
除了以上正文之外,Swift 还提供了直接以解释器执行 Swift脚本的方法,相当于在linux或mac命令行直接使用playground。 本文顺便利用这个脚本,同时说明一下动态链接库的使用方法。
默认的Swift 4为静态编译,因此如果希望使用动态链接,则需要做一个调整。 请打开Package.swift文件增加下一行:
.library(
name: "CSwift",
type: .`dynamic`, // <------------ 在这里增加新的一行
targets: ["CSwift"]),
本项目附带了一个特殊脚本dll.swift.script,内容为一个普通Swift 源程序:
// 首先dllpath 一定是编译完成的C语言动态链接库,在mac上是.dylib文件,在linux上是.so文件
// 请注意dllpath 一定是绝对路径
guard let lib = dlopen(dllpath, RTLD_LAZY) else {
exit(0)
}
// 然后声明需要引用的函数类型
typealias AddFunc = @convention(c) (CInt, CInt) -> CInt
// 用dlsym方法真正获取目标函数的地址
guard let c_add = dlsym(lib, "c_add") else {
dlclose(lib)
exit(0)
}
// 将动态函数库函数地址绑定到刚才声明的函数类型上
let add = unsafeBitCast(c_add, to: AddFunc.self)
// 调用动态链接库
let x = add(1, 2)
print(x)
// 释放资源
dlclose(lib)
附件中还包括了另外一个bash脚本dll.sh,供运行上述脚本并调用动态链接库
# 首先编译一下C函数库
swift build
# 然后判断操作系统类型,如果是苹果则使用.dylib,如果是Linux就用.so
if swift --version|grep apple
then
SUFFIX=dylib
else
SUFFIX=so
fi
# 合成动态函数库名称
DLL=$PWD/.build/debug/libCSwift.$SUFFIX
# 用swift 解释器调用脚本,并执行动态链接库调用
swift dll.swift.script $DLL
如果您在使用Xcode,则需要使用swift package generate-xcodeproj
。