В диспетчере пакетов Swift отсутствует библиотека после переноса

Я пытаюсь создать оболочку вокруг библиотеки C для Swift, но когда я импортирую ее в свой проект Xcode, я получаю сообщение об ошибке, которое

Отсутствует необходимый модуль «Clibsodium»

Я не уверен, откуда он пытается получить это имя. Моя оболочка имеет это для 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"])
    ]
)

И тогда мой module.modulemap выглядит так:

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

и shim.h просто включает правильный заголовок:

#ifndef CLIB_SWIFT_SODIUM
#define CLIB_SWIFT_SODIUM

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

#endif

На моем Mac, если я запускаю pkg-config --libs libsodium, он говорит следующее:

-L/usr/local/Подвал/libsodium/1.0.16/lib -lsodium


person Gargoyle    schedule 24.12.2018    source источник


Ответы (1)


Я исправил определение библиотеки Clibsodium как явного модуля. Сделав это, вы можете импортировать его через структуру Sodium, например import Sodium.Clibsodium, и исправить с помощью этого отсутствующий отсутствующий необходимый модуль «Clibsodium».

Я вдохновил свое решение на:

Чтобы импортировать библиотеку C в Swift, ее сначала нужно объявить как модуль. Декларация принимает форму карты модуля — файла, описывающего заголовки для импорта и статические библиотеки для связывания. Полученный модуль можно импортировать в Swift (исходно) и Objective-C (используя ключевое слово @import).

Этот способ встраивания библиотеки C в фреймворк будет работать для вас в большинстве случаев (узнайте больше об этом подходе здесь и там). Это абсолютно законно, если вы разрабатываете какую-то внутреннюю структуру или просто разбиваете свое приложение на отдельные части. Однако это не работает, когда вам нужно отправить свою библиотеку внешним пользователям через Carthage, Cocoapods или в виде бинарного файла. Основная причина в том, что полученный фреймворк нельзя переносить между компьютерами. При компиляции полученный фреймворк привязывается к текущему расположению заголовков и библиотек из карты модулей на вашем компьютере. Вы можете сразу использовать его в своем проекте, но если вы попытаетесь отправить его кому-то другому, он не сможет связать его с проектом, потому что файлы, на которые ссылается карта модуля, больше не доступны.

из этой статьи, где вы можете найти шаг за шагом как достичь этого с преимуществами и недостатками этого подхода.

В основном, что вам нужно сделать, это:

  • Создайте файл Sodium.modulemap и добавьте его в корень вашего проекта.
  • Внутри Sodium.modulemap вы можете определить библиотеку Clibsodium как явный модуль, например:

    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 не следует добавлять в какую-либо цель и должен быть указан в Настройки сборки — Упаковка — Карта модуля (MODULEMAP_FILE) = $SRCROOT/GifSwift/GifSwift.modulemap

  • Файлы Clibsodium должны быть добавлены в цель фреймворка как частный заголовок и связанная статическая библиотека (libsodium-x.a)
  • Замените операторы import Clibsodium на Sodium.Clibsodium.

Теперь вы можете использовать фреймворк Sodium в любом проекте без ошибки отсутствия модуля, потому что Sodium будет искать библиотеку внутри контейнера .framework.

person FedeH    schedule 20.12.2019