I'm creating a new iOS app in Xcode 11 (beta 5) and I'd like to try using Swift Package Manager instead of CocoaPods for managing dependencies.
A common pattern when using SwiftLint and CocoaPods is to add SwiftLint as a dependency and then add a build phase to execute ${PODS_ROOT}/SwiftLint/swiftlint
; this way all developers end up using the same version of SwiftLint.
If I try to add SwiftLint as a SwiftPM dependency in Xcode, the executable target that I need is disabled:
I was able to fake it by creating a dummy Package.swift
with no products or targets and running swift run swiftlint
in my build phase, but it feels hacky and weird:
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "dummy-package",
products: [],
dependencies: [
.package(url: "https://github.com/realm/SwiftLint.git", from: "0.34.0")
],
targets: []
)
Is there a way do this without creating a dummy package? Or is Swift Package Manager just not the right tool for this particular use case?
All methods of abusing iOS code dependency managers to run build tools are hacky and weird.
The correct way to version SPM-compliant tool dependencies is to use Mint: A package manager that installs and runs Swift CLI packages. See also Better iOS projects: How to manage your tooling with mint.
I use xcodegen to genreate a Xcode project that has the ability to run scripts. This lets me see swiftlint warnings in Xcode while developing packages.
This tool creates a Xcode project from a project.yml definition. In that definition, you can add a script that runs swiftlint as a post compile task. Example.
Advantages of this method:
Disadvantages:
A word about generating a bundle accessor. This is needed when working from a Xcode project because only SPM generates the file resource_bundle_accessor.swift
to the project. If you already compiled after opening the Package.swift
with Xcode, the file should be here:
find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift
You can add it to the project, but if you are creating a framework, the bundle accessor can be as simple as:
import class Foundation.Bundle
// This file is only used when using a xcodegen-generated project.
// Otherwise this file should not be in the path.
private class BundleFinder {}
extension Foundation.Bundle {
static var module = Bundle(for: BundleFinder.self)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With