如何在Swift中调用C库(完结篇)

jopen 6年前

上篇如何在 Swift中调用C库(进阶篇) 中,我们已经解决了大部分的问题,本篇我们来讲讲如何完善这个示例。

之前我们的示例中包含了以下几个项目:

  • hiredis-bridge 用于桥接兼容hiredis库中的一些方法。
  • CHiredis 用于映射hiredis和hiredis-bridge中的方法到Swift中去。
  • SwiftHiredis 通过CHiredis来调用hiredis和hiredis-bridge中的方法。

这些项目都是运行在Linux平台下,我们来看看如何将这个示例兼容Mac平台。

在Mac上安装Reids和Hiredis

使用Homebrew来安装:

brew install redis hiredis

然后使用下面命令运行redis:

redis-server /usr/local/etc/redis.conf

修改hiredis-bridge

主要是要修改hiredis-bridge的Makefile

TARGET = hiredis_bridge  LIB_NAME = hiredis_bridge    PREFIX ?= /usr/local    UNAME := $(shell uname)    all: $(TARGET)    $(TARGET): *.c  ifeq ($(UNAME), Linux) # build for linux      clang -c *.c      ar -rcs lib$(LIB_NAME).a *.o  endif  ifeq ($(UNAME), Darwin) # build for darwin      clang -c *.c -I$(PREFIX)/include      clang -dynamiclib *.o -I$(PREFIX)/include $(PREFIX)/lib/libhiredis.dylib -o lib$(LIB_NAME).dylib  endif      rm *.o    install:      mkdir -p $(TARGET)/usr/local/lib      mkdir -p $(TARGET)/usr/local/include/$(TARGET)      cp *.h $(TARGET)/usr/local/include/$(TARGET)  ifeq ($(UNAME), Linux)      # copy .a      cp lib$(LIB_NAME).a $(TARGET)/usr/local/lib/      rm lib$(LIB_NAME).a  endif  ifeq ($(UNAME), Darwin)      # copy .dylib      cp lib$(LIB_NAME).dylib $(TARGET)/usr/local/lib/      rm lib$(LIB_NAME).dylib  endif      mkdir -p $(PREFIX)      cp -r $(TARGET)/usr/local/* $(PREFIX)/      rm -r $(TARGET)

Makefile主要作用是编译,然后把hiredis-bridge的头文件和库文件放到对应的位置上去。不过因为Linux和Mac环境的区别,编译的方法会不一样。Linux编译出来是静态库,后缀为.a;Mac需要编译出动态库,后缀为.dylib。然后都会把头文件(.h)放到/usr/local/include/目录下,库文件(.a或.dylib)放到/usr/local/lib/目录下。

代码更新到github上: https://github.com/fengluo/hiredis-bridge/tree/c3a7f568bde781a37ebd29584a6357129284d1f6 tag: 0.2.0

创建CHiredis-OSX

hiredis在Linux和Mac下的安装位置不一样。Linux下,hiredis的头文件位置在/usr/include/,而Mac下则位于/usr/local/include/。SPM(Swift Package Manager)在 文档 中有提到过这个问题,并声称会在将来解决。我们现在的解决方法则是创建一个新的映射库。

只要把之前的 CHiredis 复制过来,修改module.modulemap中的header路径即可:

module CHiredis [system] {      header "/usr/local/include/hiredis/hiredis.h"      header "/usr/local/include/hiredis_bridge/hiredis-bridge.h"      link "hiredis"      link "hiredis_bridge"      export *  }

并且需要在Package.swift中定义包的名称,否则编译后这个包会以CHiredis-OSX为名出现。

import PackageDescription    let package = Package(    name: "CHiredis"  )

代码上传到github上: https://github.com/fengluo/CHiredis-OSX tag: 0.2.0

修改SwiftHiredis

在SwiftHiredis,我们需要基于现在的系统平台来选择依赖的映射库:CHiredis or CHiredis-OSX。只要简单的改动即可:

import PackageDescription    #if os(OSX)      let CHiredisURL = "https://github.com/fengluo/CHiredis-OSX.git"  #else      let CHiredisURL = "https://github.com/fengluo/CHiredis.git"  #endif    let package = Package(      dependencies: [          .Package(url: CHiredisURL, majorVersion: 0, minor: 2)]  )

这样对于该示例的跨平台兼容就解决了。在SwiftHiredis编译运行测试一下:

swift build  .build/debug/SwiftHiredis

就会得到上篇文章一样的结果 1234 。

代码更新到github上: https://github.com/fengluo/SwiftHiredis/tree/b1927cc9680103e51c9d114a18427d49c26d461f tag: 0.3.0

总结

至此,『如何在Swift中调用C库』这个系列我就写完了,基本上都是经验之谈。以后会继续讲解Swift在服务端的开发。

Enjoy it!

来自: http://hearrain.com/2016/01/855