Gargoyle
Gargoyle

Reputation: 10375

Swift package Manager missing library after wrap

I'm trying to generate a wrapper around a C library for Swift but when I import it into my Xcode project I'm getting an error that

Missing required module 'Clibsodium'

I'm not sure where it's trying to get that name from. My wrapper has this for the Package.swift

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "Sodium",
    pkgConfig: "libsodium",
    providers: [
        .brew(["libsodium"]),
        .apt(["libsodium-dev"])
    ]
)

And then my module.modulemap looks like so:

module Sodium [system] {
  header "shim.h"
  link "sodium"
  export *
}

and shim.h just includes the proper header:

#ifndef CLIB_SWIFT_SODIUM
#define CLIB_SWIFT_SODIUM

#ifdef __APPLE__
    #include "/usr/local/include/sodium.h"
#else
    #include "/usr/include/sodium.h"
#endif

#endif

On my mac, if I run pkg-config --libs libsodium it says this:

-L/usr/local/Cellar/libsodium/1.0.16/lib -lsodium

Upvotes: 1

Views: 443

Answers (1)

FedeH
FedeH

Reputation: 1373

I fixed the defining the Clibsodium lib as an explicit module. Doing that you can import it via the Sodium framework like import Sodium.Clibsodium and fixing with that the missing Missing required module 'Clibsodium'

I inspired my solution on:

In order to import C library into Swift, it first need to be be declared as a module. Declaration takes the form of a module map — a file describing headers to import and static libraries to link with. The resulting module may be imported into Swift (natively) and Objective-C (using @import keyword).

This way of embedding C library into a framework will work for you in most cases (learn more about this approach here and there). It is totally legit as long as you’re developing some internal framework or simply modularising your application into separate parts. However, it doesn’t work well when you need to ship your library to external users via Carthage, Cocoapods or as a binary. The main reason being that the resulting framework is not portable between computers. When undergoing compilation, your resulting framework is bound to the current location of headers and libraries from module map on your computer. You can use it right away in your project but should you try to send it to somebody else they will not be able to link it to a project because files referenced by module map are no longer accessible.

from this article where you can find step by step how to achieve it with the advantage and disadvantage of this approach.

Basically what you need to do is:

  • Create the Sodium.modulemap file and add it to the root of your project
  • Inside Sodium.modulemap you can define the Clibsodium library as an explicit module like:

    framework module Sodium {
        umbrella header "Sodium.h"
    
        explicit module Clibsodium {
            private header "version.h"
            private header "crypto_pwhash_argon2id.h"
            private header "export.h"
            private header "core.h"
            private header "crypto_aead_aes256gcm.h"
            private header "crypto_aead_chacha20poly1305.h"
            private header "crypto_aead_xchacha20poly1305.h"
            private header "crypto_auth.h"
            private header "crypto_auth_hmacsha256.h"
            private header "crypto_auth_hmacsha512.h"
            private header "crypto_auth_hmacsha512256.h"
            private header "crypto_box.h"
            private header "crypto_box_curve25519xsalsa20poly1305.h"
            private header "crypto_core_hsalsa20.h"
            private header "crypto_core_hchacha20.h"
            private header "crypto_core_salsa20.h"
            private header "crypto_core_salsa2012.h"
            private header "crypto_core_salsa208.h"
            private header "crypto_generichash.h"
            private header "crypto_generichash_blake2b.h"
            private header "crypto_hash.h"
            private header "crypto_hash_sha256.h"
            private header "crypto_hash_sha512.h"
            private header "crypto_kdf.h"
            private header "crypto_kdf_blake2b.h"
            private header "crypto_kx.h"
            private header "crypto_onetimeauth.h"
            private header "crypto_onetimeauth_poly1305.h"
            private header "crypto_pwhash.h"
            private header "crypto_pwhash_argon2i.h"
            private header "crypto_scalarmult.h"
            private header "crypto_scalarmult_curve25519.h"
            private header "crypto_secretbox.h"
            private header "crypto_secretbox_xsalsa20poly1305.h"
            private header "crypto_secretstream_xchacha20poly1305.h"
            private header "crypto_shorthash.h"
            private header "crypto_shorthash_siphash24.h"
            private header "crypto_sign.h"
            private header "crypto_sign_ed25519.h"
            private header "crypto_stream.h"
            private header "crypto_stream_chacha20.h"
            private header "crypto_stream_salsa20.h"
            private header "crypto_stream_xsalsa20.h"
            private header "crypto_verify_16.h"
            private header "crypto_verify_32.h"
            private header "crypto_verify_64.h"
            private header "randombytes.h"
            private header "randombytes_internal_random.h"
            private header "randombytes_sysrandom.h"
            private header "runtime.h"
            private header "utils.h"
         }
    
      export *
      module * { export * }
    }
    
  • Sodium.modulemap should not be added to any target and must be specified in Build Settings — Packaging — Module Map (MODULEMAP_FILE) = $SRCROOT/GifSwift/GifSwift.modulemap

  • Clibsodium files must be added to framework target as Private Header and linked static library (libsodium-x.a)
  • Replace the import Clibsodium statements with Sodium.Clibsodium

Now you can use the Sodium framework in any project without having the missing module error because Sodium will look for the library inside the .framework container

Upvotes: 1

Related Questions