xCode SPM multiple targets named - swift

In my project I have two dependencies
.package(name: "Web3swift", url: "https://github.com/skywinder/web3swift.git", from: "3.0.6"),
.package(name: "Random", url: "https://github.com/vapor-community/random.git", .upToNextMinor(from: "1.2.0"))
the Random package also has Core dependencies (https://github.com/vapor/core.git), and the target package name Web3swift also has Core in it
let package = Package(
name: "Web3swift",
platforms: [
.macOS(.v10_15), .iOS(.v13)
],
products: [
.library(name: "web3swift", targets: ["web3swift"])
],
dependencies: [
.package(url: "https://github.com/attaswift/BigInt.git", .upToNextMinor(from: "5.3.0")),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.5.1"))
],
targets: [
.target(name: "secp256k1"),
.target(
name: "Core",
dependencies: ["BigInt", "secp256k1", "CryptoSwift"]
),
.target(
name: "web3swift",
dependencies: ["Core", "BigInt", "secp256k1"],
exclude: excludeFiles,
resources: [
.copy("./Browser/browser.js"),
.copy("./Browser/browser.min.js"),
.copy("./Browser/wk.bridge.min.js")
]
),
Now I have a problem:
multiple targets named 'Core' in: 'core', 'web3swift'; consider using the `moduleAliases` parameter in manifest to provide unique names
Can you please explain how to fix this?

When you look at the developer documentation, you'll note that this is only supported in Swift 5.7+. To fix the "...is unavailable" message, you'll need to update the header in Package.swift to: // swift-tools-version:5.7 (also requires XCode > 14).
For full details, you can refer to:
The Swift 5.7 release notes
The evolution proposal: SE-0339
AFAICT, your changes look correct.

Related

Adding swift-docc-plugin to my project makes Swift 5.5 builds fail

I have a project that I recently added swift-docc-plugin to, so that I can export the DocC documentation as a static website.
// swift-tools-version:5.5
import PackageDescription
let package = Package(
name: "Saga",
platforms: [
.macOS(.v12)
],
products: [
.library(name: "Saga", targets: ["Saga"]),
.executable(name: "watch", targets: ["SagaCLI"])
],
dependencies: [
.package(url: "https://github.com/kylef/PathKit", from: "1.0.1"),
.package(url: "https://github.com/JohnSundell/Codextended.git", from: "0.1.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", branch: "main"),
],
targets: [
.target(
name: "Saga",
dependencies: [
"PathKit",
"Codextended",
]
),
.executableTarget(
name: "SagaCLI",
dependencies: ["PathKit"]
),
.testTarget(
name: "SagaTests",
dependencies: ["Saga"]
),
]
)
The problem is that on Swift Package Index all builds on Swift 5.5 and below are failing:
error: package at 'https://github.com/apple/swift-docc-plugin.git' # 859caac534e94ace18b894ccd9ed301ae4aeda84 is using Swift tools version 5.6.0 but the installed version is 5.5.0 in https://github.com/apple/swift-docc-plugin.git
See https://swiftpackageindex.com/builds/1DF06709-E2CA-4F56-B793-9CC7C8FC0A9D for a full build log.
How do I solve this? I could remove swift-docc-plugin from the dependencies I guess, and add it every time I want to export the docs, but that seems like a ridiculously annoying workaround. I don't really want to increase the minimum version of my library just because of swift-docc-plugin either.
The solution was pretty easy in the end. Just add this to the end of Package.swift
#if swift(>=5.6)
package.dependencies += [
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")
]
#endif
Unfortunately, I don’t think there’s a way around that due to the way we’re testing a package by building it.
Here's some more detail: https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1633#issuecomment-1075899345

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.

Strange Link Error With Command-Line Swift Test (May Be Swift Package Manager-Related)

I'm developing a set of interlinked SPM modules as a test/demo, and I've run into a strange linker error.
The problem occurs in this example, which has a Package.swift file that looks like this:
import PackageDescription
let package = Package(
name: "Package_C",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(
name: "Package-C",
type: .dynamic,
targets: ["Package_C"])
],
dependencies: [
.package(name: "Package_A", url: "git#github.com:LittleGreenViper/SPMArticle-Package_A.git", from: "1.0.0")
],
targets: [
.target(
name: "Package_C",
dependencies: [
.product(name: "Package-A", package: "Package_A")
],
path: "src"
),
.testTarget(
name: "Package_CTests",
dependencies: [
"Package_C"
],
path: "test"
)
]
)
The package builds fine with swift build, and everything works great, when run from Xcode.
The issue happens when I run swift test. I get the following error:
Undefined symbols for architecture x86_64:
"_$s9Package_CAAV6indentABSi_tcfC", referenced from:
_$s14Package_CTests4testC0C7QuicklyyyFSSyKXEfu_ in Package_CTests.swift.o
ld: symbol(s) not found for architecture x86_64
[4/5] Linking Package_CPackageTests
It looks like Package_C is not being linked in, but everything appears to be absolutely kosher (also, remember that everything else works fine. swift test is the only place this fails).
It should be noted that this project works fine, and does almost exactly the same thing.
The only difference that I can see, is the naming conventions of the directories. I'd really hate for that to be the issue, but I'll mess around with that, next.
Can anyone see what I can't see?
EDITED TO ADD: I should note that the static/dynamic thing doesn't seem to be the issue. I get the same error, even when I change Package_C to static.
Ugh. Looks like the issue is that the naming convention needs to be followed.
I switched from this:
To this:
and it started working. No file contents (other than removing the two path arguments from the Package.swift file) were changed.
Here is the new Package.swift file:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "Package_C",
platforms: [
.iOS(.v11),
.tvOS(.v11),
.macOS(.v10_14),
.watchOS(.v5)
],
products: [
.library(
name: "Package-C",
type: .dynamic,
targets: ["Package_C"])
],
dependencies: [
.package(name: "Package_A", url: "git#github.com:LittleGreenViper/SPMArticle-Package_A.git", from: "1.0.0")
],
targets: [
.target(
name: "Package_C",
dependencies: [
.product(name: "Package-A", package: "Package_A")
]
),
.testTarget(
name: "Package_CTests",
dependencies: [
"Package_C"
]
)
]
)

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