Importing modules with Swift package manager - swift

I am trying to use Swift's package manager to import external modules in my project. My first module come from the Vapor project. I cannot seem to get it working. I start with
swift package init
swift package generate-xcodeproj
My Package.swift looks like this:
import PackageDescription
let package = Package(
name: "OpenTools",
products: [
.library(
name: "OpenTools",
targets: ["OpenTools"]),
],
dependencies: [
.package(url: "https://github.com/vapor/json.git", from: "2.0.0")
],
targets: [
.target(name: "OpenTools", dependencies: ["JSON"]),
]
)
I then run
swift package update
swift package generate-xcodeproj # to regenerate with dependencies
and then try to import the JSON package in my main file
import JSON
The modules are there as shown below but the import gets back with an No such module 'JSON' error.
Any thoughts?

Probably the problem lies within Xcode, as it does not know yet that JSON exists, because it was not built yet. This can easily be solved by just building your project (with cmd-B). With the generated xcodeproj, Xcode should know that it first needs to build JSON and then the rest, because JSON is marked as a dependency for your target.
You can check this, by navigating in Xcode to your target (when you click on the project description file) and afterwards to "Build Phases". Under Target Dependencies you should find your JSON module.
In addition you should find a JSON module under your targets, which compiles the sources you gathered from github.
Your project should also build when executing swift build in your project root.

With Xcode 11 you should be able to open Package.swift directly which will give you a proving ground for verifying the package manifest (aka: the Package.swift file) and compiling the target. This should help see what is actually causing the error that's preventing the module from being compiled.

Related

No such module in a Swift Package using Xcode - package listed in dependencies

I create a blank template package:
> swift package init --name Temp
> open Package.swift
Xcode Version 13.2.1 (13C100) opens the package.
I add a dependency to the package.
dependencies: [
.package(url: "https://github.com/johnsundell/publish.git", from: "0.7.0")
],
Xcode > Product > Build succeeds at this point.
I edit Temp/Sources/Temp/Temp.swift to insert the first line the package that is defined in dependencies.
import Publish
A build now generates the following error:…/Temp/Sources/Temp/Temp.swift:1:8: error: no such module 'Publish'.
I feel certain this is an Apple bug. Or I could be missing something.
There are several posts about this problem when there is an xcodeproj and the additional structure that provides. Some of them hint at workarounds that help some people.
Has anyone seen this and/or know of how to resolve it?
Apple's Creating a Standalone Swift Package with Xcode document doesn't provide any insight.
thanks for the chatter in the comments, #Larme & #koen, it helped
The issue was user error (and/or a documentation lapse). Living on the (bleeding) edge.
Sometimes updates from changes are slow or require a clean or a relaunch.
Xcode auto-generates Schemes from the targets defined in your package. My build was targeting MyTarget.
Two things were missing:
name: "Publish" was not included in the package dependency - it's needed so you can reference it below (or maybe this can be derived, it's hard to tell because of Xcode refresh issues), and
a reference is needed in the dependencies for each target using the package-dependency, i needed to add dependencies: ["Publish"] in the related target
dependencies: [
.package(name: "Publish", url: "https://github.com/johnsundell/publish.git", from: "0.7.0")
],
…
targets: [
.target(
name: "MyTarget",
dependencies: ["Publish"]),
]

Cant run/find Executable Swift Package

Bottom line I am trying to run an executable from a swift package I created and linked to my target.
I think I'm missing something here, so I've created an executable swift package with the content
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "AutoLocalized",
platforms: [
.macOS(.v10_15), .iOS(.v12)
],
products: [
.executable(name: "autolocalized", targets: ["AutoLocalized"])
],
targets: [
.target(name: "AutoLocalized", dependencies: []),
.testTarget(name: "AutoLocalizedTests", dependencies: ["AutoLocalized"]),
]
)
so as I understand adding the ".executable" outputs a file I can then run via Xcode.
I am trying to run a build phase script using that output but I dont know how to access it.
When I try to add dependencies to my target I can find the "autolocalized" executable
but building the project I get an error:
After a lot of searching I found A way, maybe not the best but it workes.
So what I did is adding the package via SPM but without a dependency to any target, that means I had to make sure I build the package manually, finding it in the Build folder and using it directly from there, this was the only way I found to run mac os scripts using build phases in Xcode, I am positive others tried but no one found a good answer, so here it is.

How to use Swift Package Manager's binaryTarget?

I'm trying to use Swift Package Manager's binaryTarget to include the Stripe xcframework available here https://github.com/stripe/stripe-ios/releases/tag/v19.3.0. The package manager doesn't complain, and lets me link to it, but I can't import it im. I've made a sample repo to show it here https://github.com/martyu/StripePackageTest. Am I missing something?
First of all, your example is not testable because you have forgotten to provide a version tag, so this is not a real package.
Second, and more important, I think you have a misconception about how a package works as a binary target. You seem to think that your Swift Package can contain code that sees the XCFramework. (That's why you are trying to import in the framework module in the Sources code of the package.) That's wrong. It's the app that imports the framework module. The package is merely a way of distributing the framework.
In other words, you can write a source code package or a framework-bearing package. One package cannot be both.
But of course you can write a source code package that depends on a framework-bearing package.
First, you don't need a version tag for it to be "real package". You can specify package dependencies via commit SHA and branch as well. Also you can add local package repos in xcode via file://. Note, this is NOT the same as a local dev override.
I didn't have much luck with swift build but I did get it to work fine by creating an app in Xcode and adding the package to it. I think this is what #matt is getting at. You need to import it into a project (xcode, or another SP) and then xcode will assemble all the dependencies when it ~~builds~~ feels like it.
Here's the modified Package.swift I used. I changed the name to Example (as that's presumably the SDK you are building which depends on Stripe). You can include "Stripe" in the Example library's targets if you want it embedded in its framework. Otherwise the client app just needs to import it as well (via the tickboxes when you add it in Xcode, or via dependencies in another Package.swift).
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Example",
platforms: [
.iOS(.v11)
],
products: [
.library(
name: "Example",
type: .dynamic,
targets: ["Example"]),
.library(
name: "Stripe",
targets: ["Stripe"])
],
dependencies: [],
targets: [
// I thought this was defining the Stripe binaryTarget...
.binaryTarget(name: "Stripe",
url: "https://github.com/stripe/stripe-ios/releases/download/v19.3.0/Stripe.xcframework.zip",
checksum: "fe459dd443beee5140018388fd6933e09b8787d5b473ec9c2234d75ff0d968bd"),
// ... and then linking it to the Example project here via "dependencies" ...
.target(name: "Example", dependencies: ["Stripe"], path: "Sources")
// ... so when I'm in "Example" files, I thought I'd be able to import "Stripe" to them
]
)

Cannot use Swift Package Manager

I have the latest release versions of Swift and Xcode.
I am trying to use the Swift Package Manager to use this:
.package(url: "https://github.com/matejkosiarcik/Stopwatch.git", from: "0.1.0")
However, I have spent multiple days trying how to figure out how to embed this in my command line tool, or even in a brand new command line tool so that in Main.swift it doesn't give the error:
No such module 'Stopwatch'.
Would someone please explain how to do it for this exact package?
Thank you.
Note that the modules in a Swift Package are specified as targets, not as products.
Suppose you have the following product spec in your Package.swift:
products: [ .library(name: "MyProduct", targets: ["MyTarget1", "MyTarget2"])]
Then in some other package you use this product as a dependency in Package.swift:
.target(name: "TargetInSomeOtherPackage", dependencies: ["MyProduct"])
And in swift code you import modules:
import MyTarget1
import MyTarget2
In your case, you defined your product: .library(name: "Stopwatch", targets: ["lib"]). This means that you can use Stopwatch as a dependency, and import module lib in your Swift code. There is no module Stopwatch that you can import.

Swift Package Manager - How to use it

I have a project that I want to use this package in my app. I googled and follow the instructions:
//in Terminal
? mkdir SGLMath
? cd SGLMath
? swift package init --type executable
Then I open the package.swift file and change to this:
// swift-tools-version:3.1
import PackageDescription
let package = Package(
name: "SGLMath",
dependencies: [
.Package(url: "https://github.com/SwiftGL/Math.git", majorVersion: 1)
]
)
then Terminal:
? swift package fetch
Then I got this error:
error: the package has an unsupported layout, unexpected source
file(s) found:
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/EqualWithAccuracy.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/FunctionsTests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix2x2Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix3x3Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix4x4Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/SwizzleTests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Vector2Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Vector4Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/glmMatrixTests.swift
fix: move the file(s) inside a module
How can I resolve this?
What if I want to add this package into my existing Xcode project?
The project https://github.com/SwiftGL/Math.git does not have the correct Swift Package Manager format. The files in Tests directory should be in a directory with name: the module name + "Tests" ending appended, in this case SGLMathTests. You can fork the project and fix it or ask the author to fix it.
To use the project with Xcode, once you fix it:
a. Run swift package generate-xcodeproj. It will generate an Xcode project with the package.
b. Create an Xcode workspace and add to it your existing Xcode project and the generated project in the previous step. Add the framework with the package from the generated project to your existing Xcode project as a dependency. This should work.