Link 到 Swift 包内的 fat 静态库

Link to fat Static Library inside Swift Package

我正在尝试构建一个 Swift 包,它包装了一个用 C 编写的胖静态库:libndi_advanced_ios.a 来自 NewTek's Apple Advanced NDI SDK

我在 link 将预编译库(只有头文件和 .a 二进制包可用)到我的 Swift 包时遇到问题。我做了很多研究并尝试了不同的解决方案,但其中 none 有效。这是一个快速列表:

我可以 link 几十个 Whosebug 的问题和其他没有帮助的帖子,但它没有用 (a, b, c)。

目前我的配置是这样的:

With Package.swift 包含以下代码:

let package = Package(
    name: "swift-ndi",
    platforms: [.iOS(.v12)],
    products: [
        .library(
            name: "swift-ndi",
            targets: ["swift-ndi"])
    ],
    dependencies: [],
    targets: [
        .target(name: "CiOSNDI", path: "Libraries"),
        .target(
            name: "swift-ndi",
            dependencies: ["CiOSNDI"]),
        .testTarget(
            name: "swift-ndiTests",
            dependencies: ["swift-ndi"]),
    ]
    
)

您可以在 alessionossa/swift-ndi 找到整个项目。
目前唯一的结果是一些警告和模块 CiOSNDI 不构建:

我也尝试 .systemLibrary(name: "CiOSNDI", path: "Libraries/"), 使用此配置:alessionossa/swift-ndi/tree/systemLibrary;但我收到这些错误:

注意

NDI_include实际上是alias/symboliclink到/Library/NDI Advanced SDK for Apple/include,而NDI_iOS_lib指向/Library/NDI Advanced SDK for Apple/lib/iOS.

我总是在更改 Package.swift 后清理构建文件夹。

更新 10/01/2022libndi_advanced_ios.a 需要 libc++.tbd.在 Build Phases -> Link Binary With Libraries 的应用程序中 linked 很容易,但我不'知道如何在 Swift 包中 link。

需要用 .binary_target 指定二进制目标。见 docs and example here.

包裹在 .xcframework 中的静态库示例在文件命令中如下所示:

$ file GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement: Mach-O universal binary with 2 architectures: [arm_v7:current ar archive] [arm64]
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement (for architecture armv7):  current ar archive
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement (for architecture arm64):  current ar archive

创建 .xcframework 文件的一种方法是使用 Firebase 的 ZipBuilder,它从 CocoaPods podspec 文件指定的静态库中创建 .xcframework 文件。

我还需要将 NDI SDK 作为 Swift 包依赖项添加到我的应用程序中。

我发现了一些有效的方法:

您可以通过从通用库中提取瘦 arm64 库来创建 XCFramework 包:

lipo "/Library/NDI SDK for Apple/lib/iOS/libndi_ios.a" -thin arm64 -output "$STAGING_DIRECTORY/libndi.a"

然后创建一个 XCFramework 包:

xcodebuild -create-xcframework -library "$STAGING_DIRECTORY/libndi.a" -headers "/Library/NDI SDK for Apple/include" -output "$STAGING_DIRECTORY/Clibndi.xcframework"

我最终没有使用这种方法,因为在 GitHub 上托管 XCFramework 作为可下载的二进制版本需要我制作我的 repo public(参见 this issue)。

相反,我在 Package.swift:

中使用系统库目标
    targets: [
        .target(
            name: "WrapperLibrary",
            dependencies: ["Clibndi"], 
            linkerSettings: [
                .linkedFramework("Accelerate"),
                .linkedFramework("VideoToolbox"),
                .linkedLibrary("c++")
            ]),
        .systemLibrary(name: "Clibndi")
    ]

然后,我有 WrapperLibrary/Sources/Clibndi/module.modulemap 看起来像:

module Clibndi {
  header "/Library/NDI SDK for Apple/include/Processing.NDI.Lib.h"
  link "ndi_ios"
  export *
}

最后,我的应用程序目标(Xcode 项目的一部分,而不是 Swift 包)依赖于 WrapperLibrary,我不得不添加“/Library/NDI SDK for Apple/lib/iOS”(包括引号)到“构建设置”选项卡中的“库搜索路径”。

作为修改应用程序目标构建设置的替代方法,您可以将 pkg-config 文件添加到 pkg-config 搜索路径中的目录中。例如,/usr/local/lib/pkgconfig/libndi_ios.pc:

NDI_SDK_ROOT=/Library/NDI\ SDK\ for\ Apple

Name: NDI SDK for iOS
Description: The NDI SDK for iOS
Version: 5.1.1
Cflags: -I${NDI_SDK_ROOT}/include
Libs: -L${NDI_SDK_ROOT}/lib/iOS -lndi_ios

然后在您的包清单中使用 .systemLibrary(name: "Clibndi", pkgconfig: "libndi_ios")。然而,我发现这对用户来说不如将设置添加到我的应用程序目标方便。

理想情况下,您也可以将 NDI SDK 的依赖库和框架添加到 pkg-config 文件 (Libs: -L${NDI_SDK_ROOT}/lib/iOS -lndi_ios -lc++ -framework Accelerate -framework VideoToolbox),但 Swift 的 pkg-config 解析 -framework 个参数,所以我提交了一个错误:SR-15933.