July 3, 2014

Swift and Statically Linking C libraries

Posted in iPhone development, mac development tagged , , , , at 5:26 pm by tetontech

In preparation for creating a simulation engine more robust and current than the simple one I described in a previous post I decided to do some sandboxing of how to statically link and use an existing C library.

Rather than use something complex I created a simple C library that has one function, doStuff. This function is declared in the StuffStatic.h header file

//
//  StuffStatic.h
//  StuffStatic
//

int doStuff(int anInt);

 

and defined in the StuffStatic.c implementation file.

//
//  StuffStatic.c
//  StuffStatic
//

#import <stdio.h> 
#import "StuffStatic.h"

int doStuff(int anInt){
    int result = anInt * 2;
    printf("the result is %d\n",result);
    return result;
}

This code was compiled into libStuffStatic.a.

To use this library in a Swift app I added the libStuffStatic.a file and the StuffStatic directory containing the StuffStatic.h file to the project by dragging them into the Supporting Files group.

Interestingly, Xcode didn’t ask if I wanted to add the bridging header file I knew would be needed to make the C calls from within Swift. Rather than go through the process of manually adding a bridging file I used Xcode to create a junk.c file. This triggered the creation of the bridging header file and made all of the changes to the project required to use it. I then deleted the junk.c file from my project.

The bridging header file is used to do an import of the header files for the library. Any header from the library you include in this file automatically makes available anything defined in it to Swift. Because of this you can make calls to the functions in the header files directly in any Swift file without worrying about doing an include statement.

Since my swift project was just a sandbox project I decided to use the doStuff function directly in the ViewController’s viewDidLoad method. I wanted to simulate a number being calculated in Swift, passed to C, and a returned C int being used in Swift.

override func viewDidLoad() {
        super.viewDidLoad()
        let aNum = 3
        let aResult = Int(doStuff(Int32(aNum)))
        println("Swift result: \(aResult)")
    }

Xcode won’t do autoboxing for us so we have to do it ourselves. To convert the Swift Int aNum to a C int I passed aNum to the Int32 constructor. doStuff could then use it directly. Since doStuff returns a C int I passed its result to Swifts Int constructor and stored the new Swift Int in the aResult constant.

When data types are bridged between languages there is a computational speed cost. I haven’t yet tested what this cost is for Swift-to-C and C-to-Swift bridging. That is on my plate for next week.

4 Comments »

  1. Petershaw said,

    Excelent article. Thanx a lot.
    Can you explain more about the bringing thing please.
    Ps

    • tetontech said,

      In order for your swift code to use C code or libraries, you must have a bridging header file that is part of your project. This file must #include the header files containing the declarations of the C functions you wish to use.

  2. eFlynn said,

    I tried this out and it worked. I just have one doubt, I need to use a couple of C files which use some .h files i.e. I have a bunch of .c and .h files to use in the app. These files deal with memory allocation and deallocation, socket creation and other functionalities for implementing a protocol.

    Is a static library the ideal way to go about this? What about dynamic frameworks? (I’ve heard they’re supported from iOS 8)

    • tetontech said,

      I personally have not found a need to create dynamic frameworks. I’m sure others have such a need. You should be able to use dynamic frameworks if you choose. I’d just examine what the payoff would be in your specific circumstance.


Leave a comment