Swift Package depend on local Xcode project - swift

Is it possible for a Local Swift Package to depend on a Xcode Project (that creates a xcframework) in the same workspace?
I have tried things in the targets section in Package.swift file to point to the path where the local Xcode project is.
targets: [
.target(
name: "SomeJourney",
dependencies: ["OurUIFramework"]),
.binaryTarget(name: "OurUIFramework", path: "../../Frameworks/OurUIFramework")
]

Related

Swift Package - How to exclude files in root git directory from the actual Swift Package?

I am creating a Swift Package that is essentially a wrapper for multiple XCFrameworks generated from Objective-C frameworks so they can be installed via SPM.
Everything works fine as far as creating the SP and ability to add it as a dependency to an app. But I have a bunch non-essential files included in the SP's repository that I don't want to include in the actual SP - i.e. They shouldn't show up in Xcode's navigator when the SP is added as a dependency.
(These consist of the source Obj-C Frameworks, README, Changelog, Xcode Workspace for demo app, Script files for generating the XCFrameworks, etc).
Is this even possible?
Or will SPM always checkout the entire repo and make all files visible to the user?
I have tried using various permutations of the Target specifiers: source, path, exclude but to no avail.
Here is the closest I can get with a valid manifest, but when I check out the SP in a dummy Xcode app, I can still see all the files from the repo included:
// 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: "WrapperSwiftPackage",
platforms: [.iOS(.v13)],
products: [
.library(name: "WrapperSwiftPackage", targets: ["WrapperSwiftPackage"])
],
dependencies: [],
targets: [
.target(
name: "WrapperSwiftPackage",
dependencies: [
"ObjCFramework1",
"ObjCFramework2"
],
path: "", // Set to root directory so we can exclude files below
exclude: [
"CHANGELOG.md",
"Dangerfile.swift",
"README.md",
"Workspace.xcworkspace",
"Scripts/generate-xcframework.sh",
"Scripts/link_git_hooks.sh",
"Objective-C Frameworks/"
],
sources: [
"Sources/WrapperSwiftPackage/main.swift",
"XCFrameworks/ObjCFramework1.xcframework",
"XCFrameworks/ObjCFramework2.xcframework"
]
),
.binaryTarget(name: "ObjCFramework1", path: "XCFrameworks/ObjCFramework1.xcframework"),
.binaryTarget(name: "ObjCFramework2", path: "XCFrameworks/ObjCFramework2.xcframework")
]
)
Not sure if that isn't a bug though, but I've accidentaly came up to one solution for this.
If you put an empty Package.swift (I mean, one like this):
// swift-tools-version:5.5
import PackageDescription
let package = Package()
into one of project subfolders, then even though SPM is checking the subfolder out, it's excluded from Xcode navigator, and thus, from the project visibility.
I would like to know if that's a bug or is it documented somewhere, every hint is appreciated.
Works with local and remote dependencies.

Swift Package - Distribute standalone executable with bundle

I'm writing a Swift script as a standalone Swift Package. Part of this script needs to generate some files, for which I have templates.
Now, these templates are not compilable (they're HTML files); so in order to include them in the package I've included them as .copy("Templates").
When debugging my script, I can access the templates just fine, but when I try to archive the product, the executable doesn't have access to them anymore.
Here's my Package.swift:
let package = Package(
name: "flucs",
products: [
.executable(name: "Flucs",
targets: ["flucs"])
],
dependencies: [
.package(url: "https://github.com/MrSkwiggs/Netswift", .exact(.init(0, 3, 1))),
],
targets: [
.target(
name: "flucs",
dependencies: ["Netswift"],
path: "Sources",
resources: [
.copy("Templates")
]),
.testTarget(
name: "flucsTests",
dependencies: ["flucs"]),
]
)
My folder structure:
How can I distribute my script so that it also includes its resources?
SPM compiles your resources to a separate bundle but command line tool is just an executable without a bundle and any resources you add to your executable is simply ignored by Xcode (Build Phases > Copy Bundle Resources) for Release(Archive) builds.
If you look inside Bundle.module you can find:
...
// For command-line tools.
Bundle.main.bundleURL,
...
Where Bundle.main.bundleURL is a valid file url for the directory containing your command line executable so that it looks for your bundle next to your executable. And it works for Debug because XCode just compiles your resource bundle near your executable.
The simplest way to get Release executable with compiled .bundle file is build your package from command line:
swift build --configuration release
And then you can find them both in .build/release folder.

Sharing code across test targets when using the Swift Package Manager

I have some code that I need to share across test targets, while I'm using the Swift Package Manager. To do this, I have a .testTarget that I also name as a dependency in another .testTarget.
Here is a simple 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: "ExampleLib",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "ExampleLib",
targets: ["ExampleLib"]),
],
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 this package depends on.
.target(
name: "ExampleLib",
dependencies: []),
.testTarget(
name: "Common",
dependencies: ["ExampleLib"]),
.testTarget(
name: "ExampleLibTests",
dependencies: ["Common"]),
]
)
If I try to build this package in Xcode, I get the following error:
Unable to resolve build file: XCBCore.BuildFile (The workspace has a reference to a missing target with GUID 'PACKAGE-TARGET:Common')
However, if I build from the command line (swift build) or test from the command line (swift test), I get success.
I'm using Xcode 12 beta 6, but have also tried Xcode 11.5 (with a change to the Package.swift header) and get the same results.
Here is the complete Swift package example:
https://www.dropbox.com/s/h6ypvbfonnb2zyk/ExampleLib.zip?dl=0
I really would like to use this in Xcode to build for iOS. Thoughts?
I faced the same issue and solved it by defining a Target (not Test Target) instead for Common.
My Package.swift file:
// ...
.target(name: "Common", dependencies: ["App"], path: "Tests/Common"),
.testTarget(name: "AppTests", dependencies: ["App", "Common"]),
.testTarget(name: "IntegrationTests", dependencies: ["App", "Common"])
// ...

Two almost identical targets in Vapor Xcode project

I want to configure Package.swift so that one target would be an extension to another, both of them should share the same code from the one folder, but for the "extended" version there is an additional subfolder. But configuration I try with path fails with "overlapping sources" error. So, how can I make two target with the same source folder?
.target(name: "App", dependencies: [ "Vapor" ... ], exclude: [ "Subfolder" ])
.target(name: "Extended", dependencies: [ "Vapor", ... ], path: "./Sources/App")
swift build ... error: target 'Extended' has sources overlapping sources...
SwiftPM is strict about one target gets to own the files. So you will need to set up a proper dependency chain for your files.
It sounds like Extended adds more functionality to App in this case. If so you want to have App all the things it currently is. Then have Extended depend on App and build all of the things exclusive to it.
This allows 1 target to own the source files and allows Extended to use the one implementation of those files.
In my case I had one of my executableTargets path set to the root "."
.executableTarget(
name: "ServiceA",
dependencies: [Vapor..],
path: "."),
.executableTarget(
name: "ServiceB",
dependencies: [Vapor..]),
After I removed the path from the constructor in ServiceA. I was able to set the proper folders and Xcode was able to infer the path of my executable targets
Sources
|_ServiceA
|_ServiceB
.executableTarget(
name: "ServiceA",
dependencies: [Vapor..])
.executableTarget(
name: "ServiceB",
dependencies: [Vapor..]),

Swift Package Manager, how to handle fixtures?

I'm looking to integrate DVR into my tests for an HTTP request-heavy library I am writing. I'm using Swift Package Manager (on macOS 10.15 using the Xcode 11 Beta) to manage my dependencies and I'm unsure how to include my fixtures generated by DVR into my test target. How do I add my fixtures from DVR to my test target?
I've tried using the default Session configuration as well as attempting to store the fixtures in a Fixtures directory using Session(outputDirectory: "Fixtures", cassetteName: "example", testBundle: .main, backingSession: .shared)
My package file is as follows:
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Example",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Example",
targets: ["Example"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/venmo/DVR.git", from: "2.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: "Example",
dependencies: []
),
.testTarget(
name: "ExampleTests",
dependencies: ["Example", "DVR"]
)
]
)
When running my tests, I get the error [DVR] Persisted cassette at Fixtures/example.json. Please add this file to your test target
I'm unsure how to add this directory to my test target.
Looks like this may be impossible as of Swift 5.1. Swift ticket: SR-2866