Over a million developers have joined DZone.

Using a C Library in Swift

Trying to get a C library from within Swift? Here's how to use a C library in Swift, fitting with the Swift Package Manager.

· Mobile Zone

Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud, brought to you in partnership with IBM.

I'm still enjoying playing with Swift and am beginning to quite like the language. At the moment, I've only ever written with it on Linux, so I'm sure I'm making my life harder than if I was using OS X where it's more mature. On the flip side, if I ever use Swift professionally, it's most likely going to be on a Linux server as a microservice or a command line app at the other end of a queue.

One thing I've been trying to wrap my head around is getting access to a C library from within Swift and I picked libcurl as the one to try.

Getting this going with the Swift Package Manager isn't that hard once you understand what you're doing and understand its current limitations!

Firstly, install the the dev package for lib curl so that curl.h and libcurl.so are available:

sudo apt-get install libcurl4-openssl-dev

Creating the Swift Package

The Swift package manager requires all packages to have a Package.swift file. In this case, it can be empty as we're not compiling any Swift code.

$ mkdir CCurl && cd CCurl
$ touch Package.swift

(Note the convention for wrapping a C library is to start the name with a capital C and then using camelCase for the rest of the name.)

To bring in the C library, we need a module.modulemap file:

module CCurl [system] {
    header "/usr/include/curl/curl.h"
    link "curl"
    export *

With this file, we tell Swift where the curl.h header file is and that any functions in it are to be found in the lubcurl.so library.

We can now use curl C functions in a test app by pulling in our CCurl package as a dependency to our app.

However, as the Swift package manager only (currently) works with git repositories, we first need to create a git repo for CCurl and tag it:

$ git init
$ git add Package.swift module.modulemap
$ git commit -m "Initial commit"
$ git tag 0.0.1

Using a Package Within an App

We'll put our app at the same level as our library, so we change directory up a level out of the CCurl one and then make a new directory called app:

$ cd ..
$ mkdir app && cd app

As with our library, our app needs a Package.Swift, but this time we use it to list our dependency:

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "../CCurl", versions: Version(0,0,1)..<Version(1,0,0))

The Package call takes the URL to the git repository and the version criteria. Usually you'd have a git URL from GitHub or somewhere, but as we're doing this locally, we use a relative file-based one. The versions parameter enables us to put in a range of versions. In this case, I've said that I'll accept anything from 0.0.1 up to but not including 1.0.0.

For the Swift package manager to build an application, you must have a main.swift source file. You can have others, but we only need one file, so main.swift it is:

import CCurl

let handle = curl_easy_init()

print("handle = \(handle)")

Build the app using swift build and it will grab the CCurl dependency and place it in a Packages directory, build it and then build main.swift for you. The executable is placed in the .build/debug directory and in this case is simply called app

This is just a test that it works and the output on my system is:

$ .build/debug/app
handle = 0x0000000001adcbb0


That's all that's needed to wrap a C library and use it in Swift.

However, with curl you'll quickly notice that there's a wrinkle! Swift doesn't import variadic functions! It turns out thatcurl_easy_setopt() is a variadic function, so we need to find a solution, which I'll cover in my next article.

The Mobile Zone is brought to you in partnership with Strongloop and IBM.  Visually compose APIs with easy-to-use tooling. Learn how IBM API Connect provides near-universal access to data and services both on-premises and in the cloud.


Published at DZone with permission of Rob Allen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}