13 Comments

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.