[ad_1]
If you wish to study easy methods to use the Swift Bundle Supervisor you must learn my different article, as a result of that’s extra like an introduction for individuals who have by no means labored with SPM but.
Bundle sorts
There are a number of bundle sorts you can create with the swift bundle init
command. You may specify the --type
flag with the next values: empty, library, executable, system-module, manifest. You may also outline a customized bundle title by the --name
flag.
- The empty bundle will create the default file construction with out the pattern code information.
- The library sort will create a reusable library product template.
- The executable sort will create a Swift software with an executable product definition within the bundle and a
principal.swift
file as a place to begin. - The system-module sort will create a wrapper round a system supplied bundle, corresponding to libxml, we’ll speak about this in a while.
- The manifest sort will solely create a
Bundle.swift
file with out anything.
The Bundle manifest file
Each single SPM undertaking has this particular file inside it known as Bundle.swift
. I already wrote a publish about how the bundle supervisor and the Swift toolchain works behind the scenes, this time we will focus solely on the manifest file itself. Let’s get began. 📦
Each single Bundle.swift file begins with a particular remark line the place you need to outline the model of the used Swift instruments. The newest model is sort of completely different from the older ones.
Subsequent you need to import the PackageDescription framework to be able to outline your Swift bundle. This framework accommodates the bundle manifest construction as Swift objects.
import PackageDescription
That is it now you're prepared to explain the bundle itself. Oh by the way in which you'll be able to change the model of the used instruments, you'll be able to learn extra about this within the Bundle Supervisor utilization docs.
Bundle
A bundle is only a bunch of Swift (or different) information. The manifest file is the outline of what and easy methods to construct from these sources. Each single bundle ought to have a reputation, however this isn't sufficient to really generate one thing from it. You may solely have precisely one bundle definition contained in the file. That is the shortest and most ineffective one you can create. 🙈
let bundle = Bundle(title: "myPackage")
The bundle title goes for use when you find yourself importing packages as dependencies, so title your pacages rigorously. In the event you select a reserved title by a system framework there will be points with linking. If there is a battle you need to use static linking as a substitute of dynamic. In the event you generate a undertaking through the swift bundle generate-xcodeproj
command that undertaking will attempt to hyperlink all the things dynamically, however for those who open the Bundle.swift
file utilizing Xcode 11, the dependencies will likely be linked statically if this was not set explicitly within the product definition part.
Platform
A platform is principally an working system with a given model you can assist.
let bundle = Bundle(
title: "myPackage",
platforms: [
.iOS(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6),
]
)
While you add a platform you're placing a constraint on it through the required model. Each single dependency ought to match the requirement of the primary bundle platforms. Lengthy story quick if you must add assist for Apple platforms, you must specify a platform flag with a supported model, in any other case SPM will use the oldest deployment goal based mostly on the put in SDK, aside from macOS, that is going to be v10_10. Each bundle has Linux assist by default, you'll be able to't add such restrictions but, however possibly it will change within the close to future, additionally Home windows is coming.
Product
A bundle can have a number of closing merchandise (construct artifacts). At present there are two varieties of construct merchandise: executables and libraries. The executable is a binary that may be executed, for instance this is usually a command line software. A library is one thing that others can use, it's principally the general public API product illustration in your targets.
import PackageDescription
let bundle = Bundle(title: "myPackage", merchandise: [
.library(name: "myPackageLib", targets: ["myPackageLib"]),
.library(title: "myPackageStaticLib", sort: .static, targets: ["myPackageLib"]),
.library(title: "myPackageDynLib", sort: .dynamic, targets: ["myPackageLib"]),
.executable(title: "myPackageCli", targets: ["myPackage"])
], targets: [
.target(name: "myPackageLib"),
.target(name: "myPackageCli"),
])
If the library sort is unspecified, the Bundle Supervisor will robotically select it based mostly on the shopper's choice. As I discussed this earlier generated Xcode initiatives want dynamic linking, however for those who merely open the manifest file the app will likely be statically linked.
Dependency
Packages can depend on different packages. You may outline your dependencies by specifying an area path or a repository URL with a given model tag. Including a dependency into this part will not be sufficient to make use of it in your targets. You even have so as to add the product supplied by the bundle on the goal stage.
let bundle = Bundle(
title: "myPackage",
dependencies: [
.package(path: "/local/path/to/myOtherPackage"),
.package(url: "<git-repository-url>", from: "1.0.0"),
.package(url: "<git-repository-url>", .branch("dev")),
.package(url: "<git-repository-url>", .exact("1.3.2")),
.package(url: "<git-repository-url>", .revision("<hash>")),
.package(url: "<git-repository-url>", .upToNextMajor(from: "1.0.0")),
.package(url: "<git-repository-url>", .upToNextMinor(from: "1.0.0")),
.package(url: "<git-repository-url>", "1.0.0"..<"1.3.0"),
]
)
The URL is usually a GitHub URL, luckily you'll be able to add non-public repositories as nicely by utilizing an ssh key based mostly authentication. Simply use the [email protected]:BinaryBirds/viper-kit.git
URL format, as a substitute of the HTTP based mostly, if you wish to add non-public packages. 🤫
Goal
A goal is one thing you can construct, in different phrases it is a construct goal that can lead to a library or an executable. It's best to have no less than one goal in your undertaking file in any other case you'll be able to't construct something. A goal ought to at all times have a reputation, each different settings is non-compulsory.
Settings
There are a lot of settings that you need to use to configure your goal. Targets can depend upon different targets or merchandise outlined in exterior packages. A goal can have a customized location, you'll be able to specify this by setting the trail attribute. Additionally you'll be able to exclude supply information from the goal or explicitly outline the sources you need to use. Targets can have their very own public headers path and you may present construct settings each for the C, C++ and the Swift language, and compiler flags.
.goal(title: "myPackage",
dependencies: [
.target(name: "other"),
.product(name: "package", package: "package-kit")
],
path: "./Sources/myPackage",
exclude: ["foo.swift"],
sources: ["main.swift"],
publicHeadersPath: "./Sources/myPackage/headers",
cSettings: [
.define("DEBUG"),
.define("DEBUG", .when(platforms: [.iOS, .macOS, .tvOS, .watchOS], configuration: .debug)),
.outline("DEBUG", to: "yes-please", .when(platforms: [.iOS], configuration: .debug)),
.headerSearchPath(""),
.headerSearchPath("", .when(platforms: [.android, .linux, .windows], configuration: .launch)),
.unsafeFlags(["-D EXAMPLE"]),
.unsafeFlags(["-D EXAMPLE"], .when(platforms: [.iOS], configuration: .debug)),
],
cxxSettings: [
],
swiftSettings: [
.define("DEBUG"),
.define("DEBUG", .when(platforms: [.iOS, .macOS, .tvOS, .watchOS], configuration: .debug)),
.unsafeFlags(["-D EXAMPLE"]),
.unsafeFlags(["-D EXAMPLE"], .when(platforms: [.iOS], configuration: .debug)),
],
linkerSettings: [
.linkedFramework("framework"),
.linkedLibrary("framework", .when(platforms: [.iOS], configuration: .debug)),
.linkedLibrary("library"),
.linkedLibrary("library", .when(platforms: [.macOS], configuration: .launch)),
.unsafeFlags(["-L example"]),
.unsafeFlags(["-L example"], .when(platforms: [.linux], configuration: .launch)),
]),
As you'll be able to see you'll be able to outline preprocessor macros for each single language. You should use the protected instances for primary stuff, however there's an unsafeFlags case for the reckless ones. The great factor is you can assist a platform situation filter together with construct configuration to each single settings because the final param.
Out there platforms are:
.iOS
.macOS
.watchOS
.tvOS
.android
.linux
.home windows
The construct configuration will be .debug
or .launch
Take a look at targets
Take a look at targets are used to outline check suites. They can be utilized to unit check different targets utilizing the XCTest framework. They seem like precisely the identical as common targets.
.testTarget(title: String,
dependencies: [Target.Dependency],
path: String?,
exclude: [String],
sources: [String]?,
cSettings: [CSetting]?,
cxxSettings: [CXXSetting]?,
swiftSettings: [SwiftSetting]?,
linkerSettings: [LinkerSetting]?)
I believe the one distinction between a goal and a check goal is you can run a check goal utilizing the swift check
command, however from a structural perspective, they're principally the identical.
Bundle configs and system libraries
You may wrap an current system library utilizing Swift, the great thing about that is that you need to use packages written in C, CPP or different languages. I will present you a fast instance by the wonderful Kanna(鉋) - XML/HTML parser repository. I am utilizing this device rather a lot, thanks for making it Atsushi Kiwaki. 🙏
#if swift(>=5.2) && !os(Linux)
let pkgConfig: String? = nil
#else
let pkgConfig = "libxml-2.0"
#endif
#if swift(>=5.2)
let suppliers: [SystemPackageProvider] = [
.apt(["libxml2-dev"])
]
#else
let suppliers: [SystemPackageProvider] = [
.apt(["libxml2-dev"]),
.brew(["libxml2"])
]
#endif
let bundle = Bundle(title: "Kanna",
pkgConfig: "",
suppliers: [
.apt(["libsqlite-dev"]),
.brew(["sqlite3"])
],
merchandise: [
.library(name: "Kanna", targets: ["Kanna"])
],
targets: [
.target(name: "myPackage"),
.systemLibrary(name: "libxml2",
path: "Modules",
pkgConfig: pkgConfig,
providers: providers)
])
There's a module definition file on the Modules listing. You may want a module.modulemap
file to export a given library, you'll be able to learn extra about Modules on the LLVM web site.
module libxml2 [system] {
hyperlink "xml2"
umbrella header "libxml2-kanna.h"
export *
module * { export * }
}
You may outline your personal umbrella header and inform the system what to import.
#import <libxml2/libxml/HTMLtree.h>
#import <libxml2/libxml/xpath.h>
#import <libxml2/libxml/xpathInternals.h>
I barely use system libraries, however it is a good reference level. In any case, if you must wrap a system library I assume that you will have the required data to make it occur. 😅
Language settings
You may also specify the record of Swift verisons that the bundle is appropriate with. If you're making a bundle that accommodates C or C++ code you'll be able to inform the compiler to make use of a particular language customary in the course of the construct course of.
swiftLanguageVersions: [.v4, .v4_2, .v5, .version("5.1")],
cLanguageStandard: .c11,
cxxLanguageStandard: .gnucxx11)
You may see all of the presently obtainable choices within the feedback. I do not know what number of of you employ these directives, however personally I by no means needed to work with them. I am not writing an excessive amount of code from the C language household these days, however it's nonetheless good that SPM has this selection built-in. 👍
Abstract
The Swift Bundle Supervisor will not be the right device simply but, however it's on a great observe to grow to be the de facto customary by slowly changing CocoaPods and Carthage. There are nonetheless some lacking options which might be necessities for a lot of the builders. Don't fret, SPM will enhance rather a lot within the close to future. For instance the binary dependency and useful resource assist is coming alongside Swift 5.3. You may observe the bundle evolution course of on the official Swift Evolution dashboard.
You may learn extra concerning the Bundle Supervisor on the official Swift web site, however it's fairly obsolate. The documentation on Apple's web site can be very previous, however nonetheless helpful. There's a good learn me file on GitHub concerning the utilization of the Swift Bundle Supervisor, however nothing is up to date often. 😢
[ad_2]