Getting Started Using C Libraries from Swift

For a Swift project I’m working on, I need access to the CommonCrypto library so I can access HMAC functions. Apple has provided ready access to many system libraries within Swift, but CommonCrypto isn’t yet one of them. Thankfully, accessing these libraries requires only a small amount of extra work.

Getting Library Access

Before we can use the libraries, we need to inform the Swift compiler about them. There are two main ways to do this. Both will work inside a simple project, but which one you choose is impacted by the intended use of your code. The good news is that if you start with one then need to use the other later, the change is relatively easy to make.

The Objective-C bridging header

The easiest way to gain access to a library is to use the Objective-C bridging header. Since Objective-C is a superset of C, the bridging header also works to give you access to pure C libraries. If your Swift project doesn’t already have a bridging header, creating one is dead easy.

Right-click your project and add an Objective-C file. Don’t worry about what you’re going to name it; you’ll be throwing it away again soon enough.

Screen Shot 2015-02-09 at 7.59.13 PM

Once you’ve created the file, Xcode will ask you if you want to configure an Objective-C bridging header. Say yes, then delete the Objective-C file you just created. The bridging header will be named ProjectName-Bridging-Header.h (where ProjectName is the name of your project); open it up and add imports for the C libraries you want to use.

Screen Shot 2015-02-09 at 8.06.59 PM

Note that many libraries will require additional linker settings, e.g. -lfoo in Other Linker Flags to tell the linker to link in libfoo. Set these in your Xcode project build settings.

Module maps

As convenient as the bridging header is, it has one key limitation—you can’t use it inside a framework project.  The alternative is to use a module.

To do this, create a directory in your project directory named after the library you want to use. I did this in the shell, outside Xcode’s auspices, naming it CommonCrypto. Inside the directory, create a module.map file that encapsulates library settings. For CommonCrypto, module.map looks like this:

module CommonCrypto [system] {
    header "/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}

Now add the new module to Import Paths under Swift Compiler – Search Paths in your project settings. Use ${SRCROOT} in the module path (e.g. ${SRCROOT}/CommonCrypto) to insure that the project works no matter where it’s checked out.

Screen Shot 2015-02-09 at 8.41.06 PM

This makes it possible to just import CommonCrypto in your Swift files. Note that consumers of any frameworks you build using this technique are also going to have to add the module to their Swift search paths.

Using C Functions

Once you’ve informed Xcode and Swift about how to access your C libraries, you’ll be able to use them directly in Swift code. Most of this process involves figuring out which Swift types match up to which C types, a process made easier by the fact that Xcode autocompletion knows most of the important bits about them. Here’s an example for calculating an SHA1 HMAC:

func hmac_sha1(data: NSData, key: NSData) -> (NSData?) {
    var result = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH))
    if (result != nil) {
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
            key.bytes, size_t(key.length),
            data.bytes, size_t(data.length),
            result!.mutableBytes)
    }
    return result
}

To see how the call to CCHmac works, it’s instructive to check the manual page, which has this function prototype:

CCHmac(CCHmacAlgorithm algorithm, const void *key, size_t keyLength,
    const void *data, size_t dataLength, void *macOut);

Here’s how I broke it down:

  • key and data are void pointers instead of C types, which means I need to supply memory areas of appropriate size. I’ve chosen to use NSData (for the const variety, which Swift treats as immutable) and NSMutableData, using their bytes and mutableBytes properties to supply the UnsafePointers and UnsafeMutablePointers that Swift expects.
  • CCHmacAlgorithm actually maps to UInt32, but Swift has imported a type alias for it from the CommonCrypto headers, so for readability I use that conversion.
  • Similarly, keyLength and dataLength‘s size_t types are actually UInt, but again I choose to explictly use the size_t conversion here.

Further Reading

There is, of course, a lot more to using C and Swift than the bits I’ve personally touched on above. For further reading on this topic:

  • Interacting with C APIs from Apple’s Using Swift with Cocoa and Objective-C talks about the primitive C types Swift supports and other details like enumerations and pointers.
  • Using Legacy C APIs with Swift covers how to interact with C structs, including using alloc to allocate space for them.
 
Conversation
  • Kay says:

    Have you had a look at CryptoSwift? It’s really good.

    • Mattie Behrens Matt Behrens says:

      I did see CryptoSwift and it looked promising, but in this case, since I only needed to do HMAC, and since I thought the experience would be valuable anyway, I opted to explore linking CommonCrypto directly instead.

  • Paul says:

    Hi there,

    Thanks for the blog post, I tried to use the module.map “hack” to libxml, but so far I couldn’t make it, I feel that I’m missing something.

    Paul

  • Mikk Rätsep says:

    Hey,

    does the same approach applies to using a non-system c library in a swift framework?

    I haven’t been able to get the code-completion (and the import error) to work, but i’m able to build the framework. Any ideas on what might cause this? Or just some hints as to what i might be looking instead?

    (am using XCode 7b5 on El Capitan)

  • Chris Hatton says:

    Nice, good to see a Swift article tackling a less trodden topic: where did you find the specification for the module map? I need to write a custom module map for my own project but cannot find a spec for it anywhere. Thanks.

  • Kevin says:

    Why not just created separate Framework that is included inside of your SwiftFramework that includes any Objective-C or C code.

    With the dynamic frameworks you can embed other frameworks. Works like a Charm and no need to fool around with module mappings

  • matthieu says:

    Hi,

    Thanks for this tutorial. I’m trying to call libssh (http://www.libssh.org/) from Swift. My project is a Cocoa Framework.

    I am trying to make that work with the module.maps trick. I have auto-completion, it builds the project successfully, but it cannot run the tests (and I don’t have any other target that actually run the code). So it seems like a error in the way the binary is linked to the library. I tried with both static and shared libraries, but it gave the same result.
    I also tried the “Objective-C bridging header” technic, which doesn’t work for me (which was to be expected since it is said in the tutorial because I’m doing a framework.)

    Thanks for your help

    • matthieu says:

      I found a trick to make it work, so it does not make a good framework : install the dylib by adding them into the folder ~/lib (I did not want to mess up with system folders such as /usr/lib or such).
      A good solution for me would be that those dylib are properly included in the framework. But how to do that?

  • Wendy says:

    I get the error : ” Header ‘/usr/include/CommonCrypto/CommonCrypto.h’ not found “, if i use your code,and if i change the header to “/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h” ,it build success. But I do not want to write like that because the path of Xcode is not alway in Applications.Can you help me with this problem?

  • Adam Carter says:

    Hi, I’m trying to add the module map method to my Swift framework (also for the CommonCrypto library) and despite following the instructions, when I build I get the error “No such module ‘CommonCrypto’ “.

    I’m running on Xcode 7.3 on 10.11.4

    • Adam Carter says:

      Also, I think it’s worth noting that the Clang 3.9 documentation listed Don above says “For compatibility with previous releases, if a module map file named module.modulemap is not found, Clang will also search for a file named module.map. This behavior is deprecated and we plan to eventually remove it.” so it’s worth replacing the “module.map” filename with module.modulemap” :)

  • Lancer Kind says:

    Nice article about an obscure though important topic. Thanks!

  • Comments are closed.