The Swift bundle manifest file

[ad_1]

This text is a whole Swift Package deal Supervisor cheatsheet for the bundle manifest file, utilizing the newest Swift 5.2 instruments model.

Swift


If you wish to study learn how to use the Swift Package deal Supervisor you need to 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.


Package deal sorts

There are a number of bundle sorts you could create with the swift bundle init command. You possibly can specify the --type flag with the next values: empty, library, executable, system-module, manifest. It’s also possible to outline a customized bundle identify by the --name flag.

  • The empty bundle will create the default file construction with out the pattern code recordsdata.
  • The library kind will create a reusable library product template.
  • The executable kind will create a Swift utility with an executable product definition within the bundle and a important.swift file as a place to begin.
  • The system-module kind will create a wrapper round a system offered bundle, resembling libxml, we’ll discuss this afterward.
  • The manifest kind will solely create a Package deal.swift file with out anything.





The Package deal manifest file

Each single SPM undertaking has this particular file inside it referred to as Package deal.swift. I already wrote a put up about how the bundle supervisor and the Swift toolchain works behind the scenes, this time we’ll focus solely on the manifest file itself. Let’s get began. 📦

Each single Package deal.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 with the intention to outline your Swift bundle. This framework incorporates the bundle manifest construction as Swift objects.


import PackageDescription

That is it now you're prepared to explain the bundle itself. Oh by the best way you'll be able to change the model of the used instruments, you'll be able to learn extra about this within the Package deal Supervisor utilization readme.





Package deal

A bundle is only a bunch of Swift (or different) recordsdata. The manifest file is the outline of what and learn how to construct from these sources. Each single bundle ought to have a reputation, however this isn't enought to really generate one thing from it. You possibly can solely have precisely one bundle definition contained in the file. That is the shortest and most ineffective one you could create. 🙈


let bundle = Package deal(identify: "myPackage")


The bundle identify goes for use when you're importing packages as dependencies, so identify your pacages fastidiously. In case you select a reserved identify by a system framework there might be points with linking. If there is a battle you need to use static linking as a substitute of dynamic. In case you generate a undertaking by way of the swift bundle generate-xcodeproj command that undertaking will attempt to hyperlink every little thing dynamically, however if you happen to open the Package deal.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 could assist.


let bundle = Package deal(
    identify: "myPackage",
    platforms: [
        .iOS(.v13),         
        .macOS(.v10_15),    
        .tvOS(.v13),        
        .watchOS(.v6),      
    ]
)


Whenever you add a platform you're placing a constraint on it by way of the required model. Each single dependency ought to match the requirement of the principle bundle platforms. Lengthy story quick if it's essential to add assist for Apple platforms, you need to specify a platform flag with a supported model, in any other case SPM will use the oldest deployment goal primarily based on the put in SDK, apart 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 perhaps this can change within the close to future, additionally Home windows is coming.





Product

A bundle can have a number of remaining merchandise (construct artifacts). Presently there are two forms of construct merchandise: executables and libraries. The executable is a binary that may be executed, for instance this could be a command line utility. 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 = Package deal(identify: "myPackage", merchandise: [
    .library(name: "myPackageLib", targets: ["myPackageLib"]),
    .library(identify: "myPackageStaticLib", kind: .static, targets: ["myPackageLib"]),
    .library(identify: "myPackageDynLib", kind: .dynamic, targets: ["myPackageLib"]),
    .executable(identify: "myPackageCli", targets: ["myPackage"])
], targets: [
    .target(name: "myPackageLib"),
    .target(name: "myPackageCli"),
])


If the library kind is unspecified, the Package deal Supervisor will robotically select it primarily based on the shopper's desire. As I discussed this earlier generated Xcode tasks want dynamic linking, however if you happen to merely open the manifest file the app will likely be statically linked.





Dependency

Packages can depend on different packages. You possibly can outline your dependencies by specifying an area path or a repository url with a given model tag. Including a dependency into this part shouldn't be sufficient to make use of it in your targets. You even have so as to add the product offered by the bundle on the goal stage.

let bundle = Package deal(
    identify: "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 could be a GitHub url, happily you'll be able to add non-public repositories as effectively through the use of an ssh key primarily based authentication. Simply use the [email protected]:BinaryBirds/viper-kit.git url format, as a substitute of the HTTP primarily based, if you wish to add non-public packages. 🤫




Goal

A goal is one thing you could construct, in different phrases it is a construct goal that can lead to a library or an executable. It is 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 all the time have a reputation, each different settings is optionally available.


Settings

There are lots of settings that you need to use to configure your goal. Targets can rely 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 recordsdata from the goal or explicitly outline the sources you wish 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(identify: "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 could assist a platform situation filter together with construct configuration to each single settings because the final param.

Obtainable platforms are: .iOS, .macOS, .watchOS, .tvOS, .android, .linux, .home windows
The construct configuration might be .debug or .launch


Check targets

Check targets are used to outline check suites. They can be utilized to unit check different targets utilizing the XCTest framework. They appear to be precisely the identical as common targets.


.testTarget(identify: 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 could run a check goal utilizing the swift check command, however from a structural perspective, they're principally the identical.




Package deal configs and system libraries

You possibly can wrap an current system library utilizing Swift, the fantastic thing about that is that you need to use packages written in C, CPP or different languages. I am going to present you a fast instance by the wonderful Kanna(鉋) - XML/HTML parser repository. I am utilizing this device loads, 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 = Package deal(identify: "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 will 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 possibly can outline your personal umbrella header and thell the system what to import.





I barely use system libraries, however this can be a good reference level. Anyhow, if it's essential to wrap a system library I assume that you will have the required data to make it occur. 😅




Language settings

It's also possible to specify the listing of Swift verisons that the bundle is suitable with. In case you are making a bundle that incorporates C or C++ code you'll be able to inform the compiler to make use of a selected language customary in the course of the construct course of.



swiftLanguageVersions: [.v4, .v4_2, .v5, .version("5.1")],


cLanguageStandard: .c11,


cxxLanguageStandard: .gnucxx11)

You possibly can see all of the at present obtainable choices within the feedback. I do not know what number of of you utilize 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, but it surely's nonetheless good that SPM has this feature built-in. 👍



Abstract

The Swift Package deal Supervisor shouldn't be the right device simply but, but it surely's on an excellent monitor 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 many of the builders. Don't be concerned, SPM will enhance loads within the close to future. For instance the binary dependency and useful resource assist is coming alongside Swift 5.3. You possibly can monitor the bundle evolution course of on the official Swift Evolution dashboard.

You possibly can learn extra in regards to the Package deal Supervisor on the official Swift web site, but it surely's fairly obsolate. The documentation on Apple's web site can be very previous, however nonetheless helpful. There's a good readme file on GitHub in regards to the utilization of the Swift Package deal Supervisor, however nothing is up to date often. 😢


[ad_2]

Leave a Reply