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
Related
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
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.
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.
I used SPM to initialize the package and then generated xcodeproj for editing in Xcode. I added an executable in Xcode but SPM isn't picking it up when building. If I run generate-xcodeproj again using SPM, the executable product is gone. I looked into the .build folder and the executable isn't there. Right now this is my Package.swift:
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Swerver",
products: [
.library(
name: "Swerver",
targets: ["Swerver"]),
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/BlueSocket.git", from: "1.0.8"),
],
targets: [
.target(
name: "Swerver",
dependencies: [
"Socket"
],
path: "Sources/SwerverCore"),
.testTarget(
name: "SwerverTests",
dependencies: ["Swerver"]),
]
)
You can't add an executable in Xcode and have it picked up by the Swift Package Manager. You need to add it in the Package.swift file and regenerate the Xcode project.
Alternatively, add the executable to a new project that references the generated project.
Example:
> mkdir myProject && cd myProject
> swift package init --type executable
Edit Package.swift (added 1 dependency):
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "myProject",
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/someone/myProject.git", 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: "myProject",
dependencies: []),
]
)
Build it:
> swift build
Segmentation fault (core dumped)
Environment
Ubuntu 16.04 LTS
Swift version 4.1-dev (LLVM 260a172ffb, Clang cd84be6c42, Swift 05b1b2be7c)
Is anyone aware if this was recently introduced and/or is happening with other versions of swift?
It is a bug:
Swift Bug SR-7597
https://bugs.swift.org/browse/SR-7597