Static Library and Swift

Link to fat Static Library inside Swift Package

I also needed to add the NDI SDK as a Swift package dependency in my app.

I found a couple of approaches that worked:

You can create an XCFramework bundle by extracting a thin arm64 library from the universal library:

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

Then create an XCFramework bundle:

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

I ended up not using this approach because hosting the XCFramework as a downloadable binary release on GitHub required me to make my repo public (see this issue).

Instead I am using a system library target, in my Package.swift:

    targets: [
.target(
name: "WrapperLibrary",
dependencies: ["Clibndi"],
linkerSettings: [
.linkedFramework("Accelerate"),
.linkedFramework("VideoToolbox"),
.linkedLibrary("c++")
]),
.systemLibrary(name: "Clibndi")
]

Then, I have WrapperLibrary/Sources/Clibndi/module.modulemap that looks like:

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

Finally, my application target (part of an Xcode project, not a Swift package) depends on WrapperLibrary, and I had to add "/Library/NDI SDK for Apple/lib/iOS" (including the quotation marks) to "Library Search Paths" in the "Build Settings" tab.

As an alternative to modifying the application target build settings, you could add a pkg-config file to a directory in your pkg-config search paths. For example, /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

Then use .systemLibrary(name: "Clibndi", pkgconfig: "libndi_ios") in your package manifest. I found this less convenient for users than just adding the setting to my application target, however.

Ideally you could add the NDI SDK's dependency library and frameworks to the pkg-config file as well (Libs: -L${NDI_SDK_ROOT}/lib/iOS -lndi_ios -lc++ -framework Accelerate -framework VideoToolbox), but it appears there is a bug in Swift's pkg-config parsing of -framework arguments, so I filed a bug: SR-15933.

Xcode does not find C++ static library

To make Xcode find the library you have at least two options:

  1. Set Library Search Paths under Build Settings. This may be messy because you have to make sure that you build the library for the right architecture, e.g. simulator or actual device, and use the appropriate path.

  2. Create a new workspace, add both the library project and the app project to the workspace. In Build Phases for the app target select the static library (.a) file in the dialog that pops up after you click the + sign in the Link Binary with Libraries section. Xcode will build the library for the right architecture and link the app with the correct static lib.

Now, building the library for the correct architecture may be tricky, regardless of whether you choose option 1 or 2 above. A few things to try:

  • Create an External Build System project in Xcode and use the makefile
    that came with the library source. (File -> New -> Project... ->
    Cross-platform.)
  • Create a Cocoa Touch Static Library project in Xcode. (File ->
    New -> Project... -> iOS.) You will need to add the library
    sources to the project. This is probably your best bet if the
    library's build is not too complex.

There is also the option to include C++ library sources directly into your Swift project.

See if this post appears helpful: Compiling external C++ library for use with iOS project.

How to access pure Swift Static Library from pure Swift project?

I've passed your steps and all works, at least at Xcode 11.3.1 / iOS 13.3. The only thing... it seems... see comment

import StaticLib // << looks like you've forgot this one !!!

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {


StaticLib.test("How do you do?") // error

return true
}
}

Update: Here are my steps -

  1. Click project in Xcode Project Navigator
  2. Click + to add new target
  3. Select Frameworks & Libraries > Static Library > Next
  4. Enter name StaticLib (in Swift) > Finish
  5. Open StaticLib.swift and enter
    public class StaticLib {
public class func printme() {
print("I'm swfit static lib!")
}
}

  1. Select StaticLib schema, Build > OK
  2. Select project in Project Navigator > click main application target > select General
  3. In section Framework, Libraries, and Embedded Content click + and select libStaticLib.a > Add
  4. Select main app schema > Build > OK
  5. Select AppDelegate.swift > add import StaticLib
  6. Add anywhere in code
    StaticLib.printme()

  1. Build > OK > Run ... see output

Update2: for external Lib project

+1 It is needed to copy StaticLib.swiftmodule (it is created at the same place as libStaticLib.a) into target project folder (I placed it at the level of .xcodeproj file)

+2 In main application target Build Settings set SWIFT_INCLUDE_PATHS = ${SRCROOT}

+3 Clean > Build

Note: the indicator that module is loaded is autocompletion for import - it should show StaticLib



Related Topics



Leave a reply



Submit