Downloading Binary-only Swift Packages that require authentication - swift

I am using the Swift Package Manager that is built into Xcode 13.1 (not the command line version that uses Package.swift).
One of my dependencies is a Binary-only package. Here is what the Package.swift of that package looks like:
// swift-tools-version:5.5
import PackageDescription
let package = Package(
name: "MyLibrary",
products: [
.library(
name: "MyLibrary",
targets: ["MyLibrary"]),
],
dependencies: [],
targets: [
.binaryTarget(
name: "MyLibrary",
url: "https://gitlab.example.com/api/v4/projects/85/packages/generic/mylibrary/1.0.1/MyLibrary.xcframework.zip",
checksum: "..."
)
]
)
The binary is stored in GitLab's Generic Package Repository.
I have added the Git repository that hosts the package to my "Package Dependencies" in my project. I have generated a Personal Access Token that has API and Repository access and added it to my .netrc file:
machine gitlab.example.com
login gitlab-token
password MY_TOKEN_HERE
When I run xcodebuild -resolvePackageDependencies or use "File" -> "Packages" -> "Resolve Package Versions" in the Xcode GUI, the Git repository is cloned successfully but I get the following error message:
failed downloading 'https://gitlab.example.com/api/v4/projects/85/packages/generic/mylibrary/1.0.1/MyLibrary.xcframework.zip' which is required by binary target 'MyLibrary': badResponseStatusCode(401)
I have tried adding the same credentials to the macOS Keychain to see if Xcode can pick them up from there, but I still see the same error.
In the Swift Package Manager CLI source code, I can see that it handles crednetials for binary downloads too, but it seems that Xcode does not.
Unfortunately, I cannot switch from Xcode-integrated packaging to Package.swift packaging because other developers on the project will be confused by it.
Is it possible to get Xcode to use the .netrc credentials for downloading the file too?
Note: Cross-posted to Apple Developer Forum

Related

How to compile SwiftPackage executable product?

I have a Swift library that exports a CLI executable product. I want to ship the CLI binary as a Git release asset to ease the installation, but I am struggling to build the package.
let package = Package(
name: "swift-graphql",
platforms: [...],
products: [
// SwiftGraphQL
.library(name: "SwiftGraphQL", targets: ["SwiftGraphQL"]),
.library(name: "SwiftGraphQLClient", targets: ["SwiftGraphQLClient"]),
.library(name: "SwiftGraphQLCodegen", targets: ["SwiftGraphQLCodegen"]),
// CLI
.executable( name: "swift-graphql", targets: ["SwiftGraphQLCLI"]),
],
dependencies: [...],
targets: [...]
)
How can I build a binary executable file for swift-graphql using swift?
I have already tried swift build -c release, but I can't find the binary file that may be executed by the user, and swift build -c release --show-bin-path, but the returned path points to the folder containing all packages, not just SwiftGraphQLCLI executable.
I figured you could list all products in the package using swift package describe.
Once you find the product name of the package you want to build, you can build it using the following script
swift build -c release --product <product> --disable-sandbox

Publish CMS (by Sundell) compiling for wrong platform version

I created a new Publish: A static site generator for Swift developers project with publish new in the terminal.
When building the project in Xcode I get this error:
"The package product 'Publish' requires minimum platform version 12.0 for the macOs
platform, but this target supports 10.10"
I'm on macOS 12.4, Xcode 13.4.1, Swift 5.6.1 and Publish 0.9.0.
I've only got one installation of Xcode installed, and xcode-select points to this installation.
I've tried to set the platform version in the Package.swift file:
let package = Package(
name: "MySite",
platforms: [
.macOS(.v12_4)
],
products: [
.executable(
name: "MySite",
targets: ["MySite"]
)
],
dependencies: [
.package(name: "Publish", url: "https://github.com/johnsundell/publish.git", from: "0.7.0")
],
targets: [
.target(
name: "MySite",
dependencies: ["Publish"]
)
]
)
But this gives me another error instead:
"Reference to member 'v12_4' cannot be resolved without a contextual type" and "Cannot build "MySite" without a run destination. Select a run destination to perform this action."
I can not choose a destination because as it says: "No devices because active scheme has no targets".
And sure enough if I look at my scheme it says my target it missing, which isn't a surprise since it hasn't been build yet.
I've tried to open older projects (both my own and others) and there is no errors with them. And it's possible to choose a destination (My Mac).
I've tried to compare a new project with one of the older projects, but I can't for the better of me see where the difference in behaviour comes from.
So the question is, where to set the right platform version for compiling?
If this wasn't a Swift Package I could have set this in the Project Editor, but this option is not there for packages.
.macOS(.v12) was introduced in Package Description 5.5.
Setting it to .v12 and setting the swift-tools-version to 5.5 or above (at the top of the Package.swift file) fixes this issue.
Thanks to Joakim Danielson for solving it.

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 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 - Speech dependency not loading

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.