swiftlibcurl

Writing a Swift wrapper for the libcurl library


I tried to follow this tutorial on creating a Swift wrapper for the libcurl library but it fails with this error on #include <curl/curl.h>: 'curl/curl.h' file not found

This is my project structure:

swift_libcurl_email/
├─ Package.swift
├─ Sources/
│  ├─ libcurl/
│  │  ├─ libcurl.h
│  │  ├─ module.modulemap
│  ├─ swift_libcurl_email/
│  │  ├─ swift_libcurl_email.swift
├─ Tests/
│  ├─ swift_libcurl_emailTests/
│  │  ├─ swift_libcurl_emailTests.swift

My Package.swift:

import PackageDescription

let package = Package(
    name: "swift_libcurl_email",
    products: [
        .library(
            name: "swift_libcurl_email",
            targets: ["swift_libcurl_email"]),
    ],
    targets: [
        .systemLibrary(
            name: "libcurl",
            providers: [
                .brew(["curl"]),
                .apt(["libcurl4-openssl-dev"])
            ]
        ),
        .target(
            name: "swift_libcurl_email", dependencies: [.target(name: "libcurl")]),
        .testTarget(
            name: "swift_libcurl_emailTests",
            dependencies: ["swift_libcurl_email", .target(name: "libcurl")]),
    ]
)

My module.modulemap:

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

My libcurl.h:

#ifndef libcurl_h
#define libcurl_h

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

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

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

CURLcode curl_easy_setopt_func(CURL *handle, CURLoption option, curl_func param) {
    return curl_easy_setopt(handle, option, param);
}

CURLcode curl_easy_setopt_pointer(CURL *handle, CURLoption option, void* param) {
    return curl_easy_setopt(handle, option, param);
}

#endif /* libcurl_h */

curl is installed on my Mac using brew.

I found this repository doing the same thing, it compiles on my machine but when I try to copy its Package.swift into mine I get the following error: configuration of package 'swift_libcurl_email' is invalid; the 'providers' property can only be used with a System Module Package

Since it seems like such a simple task, I would like to have my own wrapper for the libcurl library without relying on anyone else's repo. I also want to provide some simple wrapper functions that ease the usage of curl for IMAP and SMTP tasks.

Any help is greatly appreciated, thanks!


Solution

  • I must preface this by saying that I highly recommend using URLSession directly or searching for a Objective-C wrapper of curl if you can.

    With that said, I'm trying to do the same thing but for Windows. On MacOS it works because it finds the libcurl installed on the system (that's what systemLibrary does or it installs it for you using homebrew, if I understand it correctly).

    On iOS libcurl is not available and you just can't get it from somewhere, but you can build it yourself, link it and ship it with your app.

    Maybe this repo helps. It's quite old, so I don't know if it works.

    You can also look at this repo.

    I edited the Package.swift file like this to allow it to build and run on Windows.

    .systemLibrary(
            name: "CCurl",
            path: "Sources/CCurl"
        ),
        .target(
            name: "curl-swift",
            dependencies: [
                "CCurl"
            ],
            cSettings: [
                .define("CURL_STATICLIB")
            ],
            linkerSettings: [
                .linkedLibrary("Sources/CCurl/libcurl.lib"),
            ]
        ),
    

    I'm building it as a static library here. You'll probably end up with a dynamic library or an xcframework. I think they're quite easy to bundle in a Swift package, but I don't know exactly how.

    I'll leave one more link that I hope will help somehow.

    I'm sorry I couldn't be more helpful, but I'm fighting with this myself for over a month and I still can't get it to work reliably.