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:
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.
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 -
- Click project in Xcode Project Navigator
- Click + to add new target
- Select Frameworks & Libraries > Static Library > Next
- Enter name
StaticLib
(in Swift) > Finish - Open StaticLib.swift and enter
public class StaticLib {
public class func printme() {
print("I'm swfit static lib!")
}
}
- Select
StaticLib
schema, Build > OK - Select project in Project Navigator > click main application target > select General
- In section Framework, Libraries, and Embedded Content click + and select
libStaticLib.a
> Add - Select main app schema > Build > OK
- Select AppDelegate.swift > add
import StaticLib
- Add anywhere in code
StaticLib.printme()
- 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
Difference Between Dispatch_Async and Dispatch_Sync on Serial Queue
Uigesturerecognizer on Uiimageview
How to Use Avfoundation to Crop a Video
Date to Milliseconds and Back to Date in Swift
Performance Testing in Swift Using Tdd
How to Get iOS Device MAC Address Programmatically
Uicollectionview Remove Top Padding
Get an Array of Property Values from an Object Array
"Do Not Embed", "Embed & Sign", "Embed Without Signing". What Are They. What They Do
How to Update a Localized Storyboard's Strings
Creating a Uiimage from a Uicolor to Use as a Background Image for Uibutton
Command /Usr/Bin/Codesign Failed with Exit Code 1
Sprite Moves Two Places After Being Paused and Then Unpaused
How to Pass Data from Modal View Controller Back When Dismissed
Uicollectionview Adding Image to a Cell
Swift Function Returning a Value from Asynchronous Firebase Call