Learn how to use C libraries in Swift?


Constructing a customized C library utilizing SPM

You should utilize the Swift Package deal Supervisor to create C household primarily based supply recordsdata (C, C++, Goal-C and Goal-C++) and ship them as standalone elements. If you do not know a lot in regards to the Swift Package deal Supervisor, you need to learn my complete tutorial about how SPM works. 📦

The one factor that it is advisable setup a library is a normal Package deal.swift manifest file with a barely altered listing construction to assist header recordsdata. Let’s make a MyPoint library.


import PackageDescription

let package deal = Package deal(
    title: "MyPoint",
    merchandise: [
        .library(name: "MyPoint", targets: ["MyPoint"]),
    ],
    targets: [
        .target(name: "MyPoint"),
    ]
)

Every little thing that you simply put into the header file shall be publicly obtainable for different builders to make use of, the implementation particulars are going to be situated straight underneath the Sources/[target]/ listing, however it’s a must to create a further embody folder in your headers. Let’s make a MyPoint.h file underneath the Sources/MyPoint/embody path with the next contents.

struct MyPoint {
   int x;
   int y;
};

We have simply outlined the general public interface for our library. Now for those who attempt to compile it by means of the swift construct command, it will complain that the venture is lacking some supply recordsdata. We are able to simply repair this by creating an empty MyPoint.c file underneath the Sources/MyPoint listing.

While you import an area header file to make use of in your implementation code, you’ll be able to skip the “embody” path and easily write #embody “MyPoint.h”. You may additionally put all types of C household elements into this venture, this methodology works with C++, Goal-C and even Goal-C++ recordsdata.

You may additionally place header recordsdata subsequent to the implementation supply code, however in that case the system will not have the ability to auto-locate your public (umbrella) header recordsdata, so that you additionally must create a modulemap file and supply the right location of your headers explicitly. For those who use the construction with the embody listing SPM will generate all the things for you robotically.

Congratulations, you simply shipped your first C code with Swift Package deal Supervisor. 🥳

Interacting with C libraries utilizing Swift

We’ll create a model new Swift package deal to construct an executable utility primarily based on the beforehand created C library. With a purpose to use an area package deal you’ll be able to merely specify it as with the trail argument underneath the dependencies in your Package deal.swift manifest file.


import PackageDescription

let package deal = Package deal(
    title: "Pattern",
    merchandise: [
        .executable(name: "Sample", targets: ["Sample"]),
    ],
    dependencies: [
        .package(path: "../MyPoint")
    ],
    targets: [
        .target(name: "Sample", dependencies: [
            .product(name: "MyPoint", package: "MyPoint"),
        ]),
    ]
)

This time we’re going to use the MyPoint library as an area dependency, however after all you’ll be able to handle and publish your individual libraries utilizing a git repository someplace within the cloud. Subsequent we should always create our Sources/Pattern/essential.swift file, import the library and write some code.

import MyPoint

let p = MyPoint(x: 4, y: 20)
print("Good day, world!", p.x, p.y)

If each packages can be found regionally, be sure to place them subsequent to one another, then all the things ought to work like a attraction. You possibly can open the Pattern venture manifest file utilizing Xcode as properly, the IDE can resolve package deal dependencies robotically for you, however for those who want the command line, you need to use the swift run command to compile & run the executable goal.

With this method you’ll be able to import the MyPoint module from another Swift package deal and use the obtainable public elements from it. You simply have so as to add this module as a dependency, by the best way you’ll be able to even name this module from one other C (C++, ObjC, Objc++) venture made with SPM. 😎

Learn how to use C system libraries from Swift?

There are literally thousands of obtainable instruments that you could set up in your working system (Linux, macOS) with a package deal supervisor (apt, brew). For instance there may be the well-known curl command line device and library, that can be utilized for transferring knowledge from or to a server. In different phrases, you may make HTTP requests with it, simply kind curl "https://www.apple.com/" right into a terminal window.

These system elements are often constructed round libraries. In our case curl comes with libcurl, the multiprotocol file switch library. Generally you would possibly need to use these low stage elements (often written in C) in your utility, however how will we add them as a dependency? 🤔

The reply is straightforward, we will outline a brand new systemLibrary goal in our package deal manifest file.


import PackageDescription

let package deal = Package deal(
    title: "Pattern",
    merchandise: [
        .executable(name: "Sample", targets: ["Sample"]),
    ],
    dependencies: [
        .package(path: "../MyPoint")
    ],
    targets: [

        .systemLibrary(
            name: "libcurl",
            providers: [
                .apt(["libcurl4-openssl-dev"]),
                .brew(["curl"])
            ]
        ),

        .goal(title: "Pattern", dependencies: [
            .product(name: "MyPoint", package: "MyPoint"),
            .target(name: "libcurl"),
        ]),
    ]
)

Contained in the Package deal.swift file you’ll be able to set the suppliers for the library (comparable to brew for macOS or aptitude for a lot of Linux distributions). Sadly you continue to must manually set up these packages, as a result of SPM will not do that for you, consider it as “only a reminder” for now… 😅

It will enable us to create a customized modulemap file with extra headers (common or umbrella) and linker flags inside our venture folder. First, we should always add the next modulemap definition to the Sources/libcurl/module.modulemap file. Please create the libcurl listing, if wanted.

module libcurl [system] {
    header "libcurl.h"
    hyperlink "curl"
    export *
}

The idea of modules are coming from (clang) LLVM, I extremely suggest checking the linked article if you wish to know extra about modulemaps. This manner we inform the compiler that we need to construct a module primarily based on the curl library, therefore we hyperlink curl. We additionally need to present our customized header file to make some extra stuff obtainable or extra handy. Individuals often name these header recordsdata shims, umbrella headers or bridging headers.

An umberlla header is the primary header file for a framework or library. A bridging header permits us to make use of two languages in the identical utility. The shim header works across the limitation that module maps should comprise absolute or native paths. All of them exposes APIs from a library or language to a different, they’re very comparable, however they don’t seem to be the identical idea. 🙄

In our case we will create a libcurl.h header file contained in the Sources/libcurl folder. The module map merely refers to this header file. Here is what we will place within it.

#embody <stdbool.h>
#embody <curl/curl.h>

typedef size_t (*curl_func)(void * ptr, size_t measurement, size_t num, void * ud);

CURLcode curl_easy_setopt_string(CURL *curl, CURLoption possibility, const char *param) {
    return curl_easy_setopt(curl, possibility, param);
}

CURLcode curl_easy_setopt_func(CURL *deal with, CURLoption possibility, curl_func param) {
    return curl_easy_setopt(deal with, possibility, param);
}

CURLcode curl_easy_setopt_pointer(CURL *deal with, CURLoption possibility, void* param) {
    return curl_easy_setopt(deal with, possibility, param);
}

This code comes from the archived SoTS/CCurl repository, however for those who test the shim file contained in the Kitura/CCurl package deal, you will discover a just about comparable method with much more handy helpers.

The principle motive why we want these capabilities is that variadic capabilities cannot be imported by Swift (but), so we have now to wrap the curl_easy_setopt calls, so we’ll have the ability to use it from Swift.

Okay, let me present you tips on how to write a low-level curl name utilizing the libcurl & Swift.

import Basis
import MyPoint
import libcurl

class Response {
    var knowledge = Information()

    var physique: String { String(knowledge: knowledge, encoding: .ascii)! }
}

var response = Response()

let deal with = curl_easy_init()
curl_easy_setopt_string(deal with, CURLOPT_URL, "http://www.google.com")

let pointerResult = curl_easy_setopt_pointer(deal with, CURLOPT_WRITEDATA, &response)
guard pointerResult == CURLE_OK else {
    fatalError("Couldn't set response pointer")
}
curl_easy_setopt_func(deal with, CURLOPT_WRITEFUNCTION) { buffer, measurement, n, reference in
    let size = measurement * n
    let knowledge = buffer!.assumingMemoryBound(to: UInt8.self)
    let p = reference?.assumingMemoryBound(to: Response.self).pointee
    p?.knowledge.append(knowledge, depend: size)
    return size
}

let ret = curl_easy_perform(deal with)
guard ret == CURLE_OK else {

    fatalError("One thing went flawed with the request")
}
curl_easy_cleanup(deal with)

print(response.physique)

I do know, I do know. This appears to be like horrible for the primary sight, however sadly C interoperability is all about coping with pointers, unfamiliar sorts and reminiscence addresses. Anyway, this is what occurs within the code snippet. First we have now to outline a response object that may maintain the info coming from the server as a response. Subsequent we name the system capabilities from the curl library to create a deal with and set the choices on it. We merely present the request URL as a string, we cross the end result pointer and a write perform that may append the incoming knowledge to the storage when one thing arrives from the server. Lastly we carry out the request, test for errors and cleanup the deal with.

It isn’t so unhealthy, however nonetheless it appears to be like nothing such as you’d anticipate from Swift. It is only a fundamental instance I hope it will enable you to to know what is going on on underneath the hood and the way low stage C-like APIs can work in Swift. If you wish to observe you need to strive to try the Kanna library and parse the response utilizing a customized libxml2 wrapper (or you’ll be able to examine a SQLite3 wrapper). 🤓

The system library goal characteristic is a pleasant approach of wrapping C [system] modules with SPM. You possibly can learn extra about it on the official Swift boards. If you’re nonetheless utilizing the previous system library package deal kind format, please migrate, because it’s deprecated and it will be fully eliminated afterward.

Recent Articles

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here

Stay on op - Ge the daily news in your inbox