How to use a local Swift Package which provides two libraries? - swift

I have a local swift package Foo which provides two different libraries Foo and FooB. Now I would like to use them in another local package Bar. I am only able to get the whole package by path declaration. Is there a way to name/specify which library should be used? I want to use FooB in my Bar Package.
let package = Package(
name: "Foo",
products: [
.library(name: "Foo", targets: ["Foo"]),
.library(name: "FooB", targets: ["FooB"])
]
...)
let package = Package(
name: "Bar",
dependencies: [
.package(path: "Foo"),
.package(path: "FooB") // this one does not work
],
...)
// inside package Bar
import Foo
import FooB // this is throwing "no such module 'FooB'"

Related

Including resources in swift package manager manifest

I am porting an objective c cocoa pod over to swift package manager. It has a bundle of fonts in the package. In the original pod spec, there was a link of code that created the bundle.
s.resource_bundles = {
'mathFonts' => [ 'fonts/*.otf', 'fonts/*.plist' ]
}
In the swift package, I created a static bundle, called mathFonts.bundle and added it to the package as shown below.
in the manifest file, I tried to copy the resources as shown below:
import PackageDescription
let package = Package(
name: "iosMath",
platforms: [
.iOS(.v8)
],
products: [
.library(
name: "iosMath",
targets: ["iosMath"]),
],
dependencies: [
],
targets: [
.target(
name: "iosMath",
resources: [.process("mathFonts.bundle")]), // **<- this is where I am adding the resources**
.testTarget(
name: "iosMathTests",
dependencies: ["iosMath"],
cSettings: [
.headerSearchPath("iosMath")// 5
]),
]
)
I'm getting a runtime crash here:
return [NSBundle bundleWithURL:[[NSBundle bundleForClass:[self class]] URLForResource:#"mathFonts" withExtension:#"bundle"]];
When I manually copy the bundle into the directory of the project that I am importing this package into, it works just fine. How do I include this bundle so that it is made accessible when the package is installed?

Swift - Can't import packages

I have been trying out Swift on Ubuntu 20.10 and am having trouble importing packages. Swift is installed properly. I am always getting error: no such module, no matter which package I try.
Here is my Package.swift (Embassy as an example):
// 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: "test",
/* products: [
.executable(name: "test", targets: ["test"])
],*/
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/envoy/Embassy.git",
from: "4.1.1"),
],
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 this package depends on.
.target(
name: "test",
dependencies: []),
.testTarget(
name: "testTests",
dependencies: ["test"]),
]
)
main.swift(under Sources/test)
import Foundation
import Embassy
let loop = try! SelectorEventLoop(selector: try! KqueueSelector())
let server = DefaultHTTPServer(eventLoop: loop, port: 8080) {
(
environ: [String: Any],
startResponse: ((String, [(String, String)]) -> Void),
sendBody: ((Data) -> Void)
) in
// Start HTTP response
startResponse("200 OK", [])
let pathInfo = environ["PATH_INFO"]! as! String
sendBody(Data("the path you're visiting is \(pathInfo.debugDescription)".utf8))
// send EOF
sendBody(Data())
}
// Start HTTP server to listen on the port
try! server.start()
// Run event loop
loop.runForever()
In your Package.swift file you are declaring Embassy as a dependency, but you are not referencing that dependency in any of your targets. In the example you provided, you can alter your package like this:
// 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: "test",
dependencies: [
.package(url: "https://github.com/envoy/Embassy.git", from: "4.1.1"),
],
targets: [
// Reference the 'Embassy' package here.
.target(name: "test", dependencies: ["Embassy"]),
.testTarget(name: "testTests", dependencies: ["test", "Embassy"]),
]
)

Swift Package Manager with resources compile errors

I am trying to use resources inside my Package.swift file:
// 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: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"])
],
targets: [
.target(
name: "MyPackage",
resources: [
.process("Resources/one.xml"),
.process("Resources/two.json"),
.process("Resources/three.json"),
]
)
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]
)
]
)
When I import and compile the package in another project, I am getting lots of errors, such as:
Cannot infer contextual base in reference to member 'target'
or:
Reference to member 'process' cannot be resolved without a contextual type
The files are located in my package project in Sources -> MyPackage -> Resources
I also tried .copy("Resources/one.xml"), etc
What am I missing?
You missed a , after the target close parentheses:
.target(
name: "BioSwift",
resources: [
.process("Resources/unimod.xml"),
.process("Resources/aminoacids.json"),
.process("Resources/elements.json"),
.process("Resources/enzymes.json"),
.process("Resources/functionalgroups.json"),
.process("Resources/hydropathy.json")
]
), // Here is the missed `,`
Also, you don't need to add files one by one! Instead, you can add a directory:
.process("Resources")

Strange Dependency Issue With Swift Package Manager

UPDATE: I gave it a couple of days, with no answers, so I will be starting to modify the repos, in an effort to fix the problem (I'll get it, eventually).
I am absolutely sure that "I'm not holding it right," but there's no way for me to diagnose the issue.
I have also made a similar post on the Swift Forums.
I have this package, which is consumed by this package, which is, in turn, consumed by this app. The first package is also consumed by this package, which is also consumed by the app. That chain works fine, but is also a great deal simpler.
The issue is that I get an error inside the RVS_BlueThoth package during the BlueVanClef build.
The error is consistent with the RVS_Generic_Swift_Toolbox package not building in the RVS_BlueThoth package build (the module is not available), but I can't figure out why. There is nothing but a blank serialized diagnostics file for one of the files that consumes the RVS_Generic_Swift_Toolbox module, and no other errors, other than the file isn't there.
If I build the RVS_BlueThoth package independently, I have no issues, but including it in the BlueVanClef app consistently reports this error.
Like I said, I am sure that the problem is mine. I just can't figure out how to get to it.
Thanks for any help!
(For example, is there any diagnostic utility available for SPM?)
Here's a diagram of the dependencies:
Note the dotted line between RVS_BlueThoth and RVS_Persistent_Prefs. That's because the dependency is only for test harnesses, and is not used by Blue Van Clef.
Here are the various Package.swift Files:
RVS_Generic_Swift_Toolbox:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_Generic_Swift_Toolbox",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(
name: "RVS-Generic-Swift-Toolbox",
type: .dynamic,
targets: ["RVS_Generic_Swift_Toolbox"])
],
targets: [
.target(
name: "RVS_Generic_Swift_Toolbox",
path: "./src")
]
)
RVS_Persistent_Prefs (This one works):
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_Persistent_Prefs",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(
name: "RVS-Persistent-Prefs",
type: .dynamic,
targets: ["RVS_Persistent_Prefs"])
],
dependencies: [
.package(
url: "git#github.com:RiftValleySoftware/RVS_Generic_Swift_Toolbox.git",
from: "1.2.1"
)
],
targets: [
.target(
name: "RVS_Persistent_Prefs",
path: "./src")
]
)
RVS_BlueThoth (This one does not work):
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_BlueThoth",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(
name: "RVS-BlueThoth",
type: .dynamic,
targets: ["RVS_BlueThoth"]
)
],
dependencies: [
.package(
url: "git#github.com:RiftValleySoftware/RVS_Generic_Swift_Toolbox.git",
from: "1.2.1"
),
.package(
url: "git#github.com:RiftValleySoftware/RVS_PersistentPrefs.git",
from: "1.1.1"
)
],
targets: [
.target(
name: "RVS_BlueThoth",
path: "./src/Source"
)
]
)
OK. Solved. Finally.
I was, indeed, "holding it wrong," but it was not easy to tell.
The best way to debug was to cd to the package directory, and do a swift build. That helped me to see the errors as they happened (They were not reflected in the Xcode logs).
The issue was that I needed to do the dependency in TWO places. I had it only in one. Now that I look back on it, it was a fairly natural structure, but was complicated by the fact that I needed to rename the product of the dependency to use dashes, instead of underscores.
This was fixed by changing the RVS_BlueThoth Package.swift file to like so:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_BlueThoth",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(name: "RVS-BlueThoth", type: .dynamic, targets: ["RVS_BlueThoth"])
],
dependencies: [
.package(name: "RVS_Generic_Swift_Toolbox", url: "git#github.com:RiftValleySoftware/RVS_Generic_Swift_Toolbox.git", from: "1.2.1")
],
targets: [
.target(
name: "RVS_BlueThoth",
dependencies: [.product(name: "RVS-Generic-Swift-Toolbox", package: "RVS_Generic_Swift_Toolbox")],
path: "./src/Source"
)
]
)
The money shot was this line:
dependencies: [.product(name: "RVS-Generic-Swift-Toolbox", package: "RVS_Generic_Swift_Toolbox")]
Note that the name argument is "RVS-Generic-Swift-Toolbox", NOT "RVS_Generic_Swift_Toolbox", but the package name had the underscores (I probably could do without the name argument in the global dependency list).
That is because I had to swap underscores for dashes in order to get the app to be accepted by the App Store.
I was also able to simplify the dependency chain a bit, because some dependencies were only required for test harnesses.
UPDATE: I wanted to mention that the thing that made it for me, was the error response from the swift build command. It was awesome. It actually had the code that I needed to use. It was that response that showed me that I need to use dashes, mixed with underscores. That was not something that I was understanding.

Excluding files in Swift Packages

To exclude entire sections of a file, I can use macros to target platforms such as #if os(iOS) || os(watchOS).
Is there a way to do this in Package.swift, or another way to target a few files for specific platforms in Swift Package Manager?
Is there a way to do this in Package.swift ... ?
Swifty stuff also works in Package.swift since the package declaration file is itself a .swift file.
Here are some examples which use Swift 5.3 Package Manager Conditional Target Dependencies SE-0273 condition and when.
// swift-tools-version:5.3
import PackageDescription
// ...
targets: [
.target(
name: "BKSecurity",
dependencies: [
.product(name: "Crypto", condition: .when(platforms: [.linux])),
"BKFoundation"
]),
// swift-tools-version:5.3
import PackageDescription
// ...
targets: [
.target(
name: "CombineShim",
dependencies: [
.product(name: "OpenCombine",
package: "OpenCombine",
condition: .when(platforms: [.wasi, .linux])
)]
),
.target(
name: "TokamakShim",
dependencies: [
.target(name: "TokamakDOM", condition: .when(platforms: [.wasi])),
"SomeCommonDependency"
]
),
// swift-tools-version:5.3
import PackageDescription
let supportsCoreAudio: BuildSettingCondition =
.when(platforms: [.iOS, .macOS, .tvOS, .watchOS])
let supportsALSA: BuildSettingCondition =
.when(platforms: [.linux])
let package = Package(
name: "portaudio",
// ...
targets: [
.target(
name: "libportaudio",
dependencies: [],
cSettings: [
.define("PA_USE_COREAUDIO", supportsCoreAudio),
.define("PA_USE_ALSA", supportsALSA)
],
linkerSettings: [
.linkedLibrary("asound", supportsALSA),
.linkedFramework("CoreAudio", supportsCoreAudio),
.linkedFramework("CoreServices", supportsCoreAudio),
.linkedFramework("CoreFoundation", supportsCoreAudio),
.linkedFramework("AudioUnit", supportsCoreAudio),
.linkedFramework("AudioToolbox", supportsCoreAudio)
]),
]
//...
)
Note that #if os(…) can be used in Package.swift. However, Package.swift is evaluated, built and executed in the context of the build platform. So, #if os(…) is useful in the context when the target platform is the same as the build platform e.g. macOS, Linux or Windows.
Package.swift
import PackageDescription
let package = Package(
// ...
targets: {
var targets: [Target] = [
.testTarget(
name: "QuickTests",
dependencies: [ "Quick", "Nimble" ],
exclude: ["SomeFile.ext"]
),
]
#if os(macOS)
// macOS build platform
targets.append(contentsOf: [
.target(name: "QuickSpecBase", dependencies: []),
.target(name: "Quick", dependencies: [ "QuickSpecBase" ]),
])
#else
// not macOS build platform, e.g. linux
targets.append(contentsOf: [
.target(name: "Quick", dependencies: []),
])
#endif
return targets
}(),
)
See Also
The Swift Programming Language: Statements > Conditional Compilation Block
GitHub/Apple/swift: lib/Basic/LangOptions.cpp
Currently supported compilation OSs: macOS, tvOS, watchOS, iOS, Linux, FreeBSD,OpenBSD, Windows, Android, PS4, Cygwin, Haiku, WASI
GitHub/Apple/swift-evolution: SE-0273 Package Manager Conditional Target Dependencies