Swift Package Manager - Speech dependency not loading - swift

I'm encountering an issue creating a Swift Package for my project. I have CocoaPods and Travis CI running and both are working swimmingly, however I now intend to also offer the project through the Swift Package Manager. This is where I'm running into issues. My package file is looking like the following:
// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Voxosonus",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Voxosonus",
targets: ["Voxosonus"]),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Voxosonus",
path: "Voxosonus"),
.testTarget(
name: "VoxosonusTests",
dependencies: ["Voxosonus"],
path: "VoxosonusTests"),
]
)
However when I run swift build I encounter the following:
/Users/<hidden>/Documents/Projecten/Voxosonus/Voxosonus/SpeechRecognizer.swift:8:8: error: no such module 'Speech'
import Speech
My question is - why is it unable to find the 'Speech' module? This is core functionality from Apple themselves and so far the internet has made me none the wiser. Some details on the project:
Build target: iOS 12.x
macOS: 10.14
Swift Version: 4.2.1

As explained in the Swift Package Manager Github, you can't define the target platform of a Swift Package yet:
At this time there is no explicit support for depending on UIKit,
AppKit, etc, though importing these modules should work if they are
present in the proper system location. We will add explicit support
for system dependencies in the future. Note that at this time the
Package Manager has no support for iOS, watchOS, or tvOS platforms.
So when you are try to build the library with Xcode (or with the swift build command), the compiler can't find the Speech module because it is only available on iOS 10+.
You can check this github project (swift-package-manager-ios) which provides a ruby script that modify the xcodeproj generated by the Swift Package Manager by adding the necessary information in order to build for the iOS platform.

Related

How do you build iOS specific packages using SPM?

I am using Swift Package Manager that doesn't having a xcodeproject file associated with it and I get an error when building through he terminal. When I call the swift build command I get an error that the MacOS build failed. The package I'm building doesn't support MacOS (It uses UIKit), but only iOS. I can't figure out a way to call the command to only specify that the build is targeted for iOS. I've Google searched around with no luck. Does anybody know the correct syntax if it exists to build an SPM package for iOS from the terminal?
The version of Swift I'm using is: "Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)"
I have specified the platform in the Package.swift file
let package = Package(
name: "Package",
platforms: [.iOS(.v10), ],
products: [
...
I have created a sample project on github https://github.com/mike011/Swift-Package-Manager-Example. When I run swift build it fails with
/git/Swift-Package-Manager-Example/Sources/Swift-Package-Manager-Example/iOSSpecificFile.swift:9:8: error: no such module 'UIKit'
import UIKit
^
/git/Swift-Package-Manager-Example/Sources/Swift-Package-Manager-Example/iOSSpecificFile.swift:9:8: error: no such module 'UIKit'
import UIKit
^
I "solved" this by wrapping all my files in #if !os(macOS) #endif blocks. So the package builds on a Mac, but it doesn't have any content.
SwiftPM doesn't currently have a way to disallow building for a specific platform but if you want you can take advantage of the minimum build version to cause compile time errors on platforms you don't support.
For example if you don't want to allow building on macOS you can use the platform version: .macOS("99.0") in your platforms section of your manifest and you will be given the compilation warnings and errors similar to this when building in Xcode:
The macOS deployment target 'MACOSX_DEPLOYMENT_TARGET' is set to 99.0, but the range of supported deployment target versions is 10.8 to 10.16.99
Invalid Darwin version number: macos99.0
Invalid version number in 'target x86_64-apple-macos99.0'

Runtime error with Xcode-generated project from SPM (dyld: Library not loaded, incompatible library version)

I'm building a command line tool with the Swift Package Manager, using Ink as a dependency.
I'm following this article by John Sundell for reference, and I managed to get the tool to compile and run with swift build -c release.
I also generated a corresponding Xcode project with swift package generate-xcodeproj, so that I can use the debugger and work more effectively.
However, whenever I try to run my tool from Xcode, I get this error:
dyld: Library not loaded: /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/Ink.framework/Versions/A/Ink
Referenced from: /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox
Reason: Incompatible library version: HIToolbox requires version 1.0.0 or later, but Ink provides version 0.0.0
Program ended with exit code: 9
For reference, here's my Package.swift:
import PackageDescription
let package = Package(
name: "SwiftSiteGen",
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(
url: "https://github.com/johnsundell/files.git",
from: "4.0.0"
),
.package(
url: "https://github.com/johnsundell/Ink.git",
from: "0.1.3"
),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "SwiftSiteGen",
dependencies: ["SwiftSiteGenCore"]),
.target(name: "SwiftSiteGenCore",
dependencies: ["Files", "Ink"]),
.testTarget(
name: "SwiftSiteGenTests",
dependencies: ["SwiftSiteGen"]),
]
)
I'm running on Xcode 11.2.1, on macOS 10.14.4.
Since running swiftc build works, I feel that the problem is with Xcode trying to use dynamic frameworks rather than static libraries. Possibly related question here.
Are there some Xcode project settings I need to change to make this work?
Verified Solution
Do not run swift package generate-xcodeproj.
Instead, just open Package.swift directly in Xcode.
That way, all packages are statically linked.

Swift Package Manager: dependency iOS version

I'm trying to build swift package with external dependency (CoreStore) with xCode11 beta 7. My package is targeted for iOS11+, it's declared in Package.swift:
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Storages",
platforms: [.iOS(.v11)],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Storages",
targets: ["Storages"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "6.3.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Storages",
dependencies: [.product(name: "CoreStore")]),
.testTarget(
name: "StoragesTests",
dependencies: ["Storages"]),
]
)
However, when I build it dependency builds without iOS version specified, so I get compatibility errors:
"'uniquenessConstraints' is only available in iOS 9.0 or newer" and so on.
How can I fix it? Looks like it's xCode11 bug, but I'm not sure.
On my machine, adding the platforms: parameter to the manifest solved it. For example:
let package = Package(
name: "MyLibrary",
platforms: [.iOS("13.0")],
// ...
I'm not sure is it xCode bug or not, however with Swift Package Manager and xCode 11 you have to clearly specify iOS version when use #available check. Not matter if library is targeted for iOS 10+ or not, instead of
if #available(macOS 10.11, *) {
info.append(("uniquenessConstraints", self.uniquenessConstraints))
}
you should use
if #available(macOS 10.11, iOS 9.0, *) {
info.append(("uniquenessConstraints", self.uniquenessConstraints))
}
Pull request was posted:
https://github.com/JohnEstropia/CoreStore/pull/341
First, you need to add a platform parameter and fill it out with the supported platform versions. Then, you need to clear derived data in your host app. After that, try adding the spm framework again.
I had the same thing where I didn't add the platform parameter at first and it was giving me so many "'xxx' is only available in iOS 9.0 or newer" errors in my host app. Hopefully that fixes it for you.

Swift Package Manager executable app, set deployment target

I'm using Swift Package Manager to create a macOS executable. When I use things that aren't available in all macOS versions I get compile errors. Two big examples are URL(fileURLWithPath: filePath, relativeTo: directoryToSearch) and url.hasDirectoryPath.
When building with swift build I get error: 'init(fileURLWithPath:relativeTo:)' is only available on OS X 10.11 or newer errors. I don't care about any old OS versions, as it's just a personal tool. How can I set the deployment target to be 10.14 so I don't have to sprinkle checks all through out my code?
I found https://hirschmann.io/swift-package-manager/ which talks about this issue. However it's solution is creating an xcconfig file with the deployment target set and using swift package generate-xcodeproj --xcconfig-overrides ./main.xcconfig to apply it to the generated Xcode project. While it does work, it only works for the Xcode project, so if I just want to do swift build to get the free standing executable to use outside of Xcode then I can't.
My package file was auto generated by swift package init --type executable and hasn't been changed.
// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "swift_converter",
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "swift_converter",
dependencies: []),
.testTarget(
name: "swift_converterTests",
dependencies: ["swift_converter"]),
]
)
This may not help you right now, but the upcoming Swift 5.0 will include the ability to specify the deployment target in the package manifest, using a syntax like this:
...
platforms: [
.macOS(.v10_13), .iOS(.v12),
],
...
(The same is true for some other common build settings.)
Until then, you can override the default deployment target via command line arguments like this:
$ swift build -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.14"
You'll have to include these arguments in every call to swift build, swift run, swift test.

Swift Package Manager - UIKit Dependency

I have a Package.swift in my project like:
import PackageDescription
let package = Package(
name: "ProjectName",
dependencies: [
.Package(url: "https://github.com/example/repo.git", majorVersion: 0)
]
)
When I run swift build I get errors likeā€¦
/project/Packages/WebViewController.swift:1:8: error: no such module 'UIKit'
import UIKit
^
Where should I tell the swift package manager where to find UIKit?
You have to change some swiftc options to build the project against proper sdk and target
swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios13.0-simulator"
Make it work without limit the platforms:
You should select an iOS-based target to make it available:
If you leave it selecting macOS (by default), you will get the error.
Limit to a specific platform
if you want your package to be available only for specific platforms (for example only for iOS), you should specify the platform in the package.swift file:
let package = Package(
name: "MyLibrary",
platforms: [
.iOS(.v10)
],
products: [
,,,
Support Multiplatform
If you need your framework to be available on multiple platforms, don't forget to check the availability of the imported framework like:
#if canImport(UIKit)
import UIKit
#endif
Currently Swift Package Manager has full Xcode support. I was able to get around this error by specifying in my Package.swift manifest that the platform was iOS.
let package = Package(
name: "MyPackage",
platforms: [
.iOS(.v8)
],
Then you can open the Package.swift file in Xcode and it will just work.
The Swift Package Manager builds executables to run on OS X (or Linux); UIKit is a framework in iOS and won't be accessible.
It may be iOS, tvOS and others become accessible as Swift Package Manager evolves.
On Dec 4, 2015, at 5:39 PM, Daniel Dunbar (#apple.com) wrote:
...
Right, now we only compile for the host platform (OS X or Linux, currently). Among other things, we currently have no knowledge (or options to choose) what SDK or architecture you are targeting. We also have no mechanisms for specifying what platforms targets are compatible with in the manifest.
Make sure you select an iPhone as a simulator target. a Mac target is the default and that won't work...It would be awesome if Xcode could look at the manifest and choose a default simulator based on that...
Use conditional compilation blocks:
#if canImport(UIKit)
// Code specific to platforms where UIKit is available
#endif
Source: https://developer.apple.com/documentation/xcode/creating_a_swift_package_with_xcode
If your umbrella header(<module_name.h>)[About] contains
#import <UIKit/UIKit.h>
it means that you can skip specifying import UIKit in every file. But it seems that SPM doesn't support it. Also I am not a supporter of using #_exported attribute
You can write import UIKit explicitly