How to import local xml file in my Swift program using SPM?
From Swift 5.3, it is possible to add resources using Package.swift
, which has been done in the code.
To call the added resources, it is required to use:
Bundle.module.url(forResource: myFile, withExtension: myExtension)
However, this is not possible in the extension made previously, where it was self.url
.
Thus, I deleted the extension and changed the function loadPN(filePath: String)
into:
func loadPN(filePath: String) {
if let url = Bundle.module.url(forResource: filePath, withExtension: nil) {
let parser = XMLParser(contentsOf: url)!
parser.delegate = self
parser.parse()
}
}
testDoesNotWork
test finally passed.
Can I make a local module with the Swift Package manager?
You can reference a local directory in your Package.swift
file, but it must be a Git repository. Also, initializing the repo, committing, and tagging is not sufficient; the repository must be pushed to a remote for swift build
to function correctly.
According to the SwiftPM Usage Guide:
Packages are Git repositories, tagged with semantic versions, containing a Package.swift file at their root. Initializing the package created a Package.swift file, but to make it a usable package we need to initialize a Git repository with at least one version tag.
The Swift Package Manager Documentation also states that "you can specify a URL (or local path) to any valid Swift package" and provides an example Package.swift
with a local file reference: .Package(url: "../StringExtensions", "1.0.0")
.
Note: I edited the answer to clarify that Swift Package Manager can reference a local path, but the path must contain a valid Git repository with a tag. My original test project pointed to a dependent local path that contained a .git
directory, and so it successfully built with swift build
.
Swift Package Manager Dependency Mirroring
Having an Xcode project makes this task basically impossible (at the time of writing). Xcode's integration with SPM works fine for most things, but is not (yet?) at par with what SPM can do in pure SPM packages.
The problem is, that swift package config
is always only local to the package and does not have any effect on projects / packages that depend on the package. And with Xcode currently having no counterpart to swift package config
, it's not possible to do this at the moment.
What you could do, however, is to clone all your dependencies locally and then reference them as local packages from Xcode (simply dragging the package folder into the open Xcode project will do so). Xcode will be smart enough to take the dependencies from the local local checkout (or at least it was smart enough last time I tried this).
Let's hope for a future Xcode version with full SPM support!
Adding Local dependencies in XCode11 using SPM
This is the way I did it :
- Drag and drop your package folder (in my example "DataStructures") from the finder directly into the Frameworks group of your target. You will see that the dropped item take a brown folder color (you can use the arrow to "get into it").
- Go to your project target page, in the "Framework and Libraries" click the "+" button. Your package should show up in the "Workspace" area as a library.
Swift Package Manager: How to add local shared library as dependency to multiple executables?
This should do it. You don't need to add a "dependency" to a target where all the sources are on your local computer.
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "dmx-db",
products: [
.executable(name: "DmxServer", targets: ["DmxServer"]),
.executable(name: "DmxClient", targets: ["DmxClient"]),
// This lib will be imported into both, client and server.
.library(name: "DmxLib", targets: ["DmxLib"]),
],
dependencies: [
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.21"),
.package(url: "https://github.com/codewinsdotcom/PostgresClientKit", from: "1.0.0"),
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "1.0.0-alpha.5"),
],
targets: [
.target(name: "DmxServer", dependencies: [
"DmxLib",
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "PostgresClientKit", package: "PostgresClientKit"),
.product(name: "Lifecycle", package: "swift-service-lifecycle"),
]),
.target(name: "DmxClient", dependencies: [
"DmxLib",
.product(name: "GRPC", package: "grpc-swift"),
]),
.target(name: "DmxLib", dependencies: []),
]
)
This does require that you have a Sources
directory in the root directory of your package, and inside it you have three folders, named DmxLib
, DmxClient
, and DmxServer
, respectively.
Note: I've actually updated the swift-tools-version
to 5.3, because I copied and modified this from one of my projects, but I think it should work with a swift-tools-version
of 5.2
Cleanly handling /usr/local/ with Swift package manager and libevent
What you've found out, and documented in your answer, is a good start but not the full story. Yes, SwiftPM uses pkg-config
to determine where certain libraries are installed. Yes, SwiftPM uses the pkgConfig
name which it'll pass on to pkg-config
. However the search paths are a bit more involved. On macOS it uses the following list as a base search path:
/usr/local/lib/pkgconfig
/usr/local/share/pkgconfig
/usr/lib/pkgconfig
/usr/share/pkgconfig
PKG_CONFIG_PATH
environment variable
However SwiftPM doesn't use the pkg-config
command, but instead parses .pc
files directly. By setting the pkgConfig
parameter on your package, it knows what filename to look for in the paths listed above. And, for the example in your answer, the story stops here. If there's a libevent.pc
file found it parses that file, and any flags returned are passed on to the compiler and linker.
However if you were to define package providers, e.g.:
providers: [
.Brew("libsodium"),
.Apt("libsodium-dev")
]
Then SwiftPM adds additional search paths depending on the package provider for the platform it is building for. Continuing the example of macOS, SwiftPM will run brew --prefix
. If this returns a path, the following path is added as a additional search path:
[brewPrefix]/opt/[packageName]/lib/pkgconfig
In my example of libsodium
, SwiftPM is now able to infer the location of the library without requiring brew link
or symlinks at all. In my verbose build output it lists the libsodium
library path in my cellar: -L/usr/local/Cellar/libsodium/1.0.11/lib
.
How do I use a local SPM package without a git repository?
Note that even for a local directory you have to create a git repository (local). Just run git init
in the local directory, git commit
and add a tag, e.g. git tag 1.0.0
.
Related Topics
The File "Xxx.Mp4" Couldn't Be Opened Because You Don't Have Permission to View It
Scenekit Some Textures Have a Red Hue
How to Build a Workout App on Watchos with Audio Feedback
In Swift, Why Does Assigning to a Static Variable Also Invoke Its Getter
What Is the Usecase for Ignored Parameters in Swift
What Is Other Option Available in Swift Instead of Refactoring and Renaming Class or Attribute Name
Nstextalignment.Justified for Uilabel Does Not Work
Skip Item When Performing Map in Swift
Swift 3, Xcode 8 Instantiate View Controller Is Not Working
Xcode Incorrectly Reporting Swift Access Race Condition
How to Add a Double Tap Gesture Recognizer in Swift
Vapor Toolbox Broken After Upgrading Swift
Swift Uipasteboard Not Copying Png
!? Strange Double Unwrapped Optional Syntax in For_In []
Using "If Let" with Logical "Or" Operator