Swift Package Manager 是苹果推出的用于创建使用swift的库和可执行程序的工具。
能够通过命令快速创建library或者可执行的swift程序,能够跨平台使用,能够使开发出来的项目能够在不同平台上运行。
1、目前只能用来写跨平台的项目,如swift服务端开发,现在的Vapor、Perfect等服务端的web框架均使用SwiftPM来构建和管理依赖。 2、iOS和MacOS目前还未支持,但是后续一定会支持,现在只需要耐心的等待。
注意:本文适用于Swift 4.1.0 版本,后续会有更新,如果里面的demo不能正常运行,请检查版本。
1、创建文件夹,并进入文件夹
$ mkdir Hello $ cd Hello
2、初始化一个名为Hello的package
$ swift package init
会生成以下的文件结构
Hello项目的目录结构
3、使用命令行编译项目
$ swift build Compile Swift Module 'Hello' (1 sources)
使用命令行运行test
$ swift test Compile Swift Module 'HelloTests' (2 sources) Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackageTests.xctest/Contents/MacOS/HelloPackageTests Test Suite 'All tests' started at 2018-08-28 11:23:16.755 Test Suite 'HelloPackageTests.xctest' started at 2018-08-28 11:23:16.755 Test Suite 'HelloTests' started at 2018-08-28 11:23:16.755 Test Case '-[HelloTests.HelloTests testExample]' started. Test Case '-[HelloTests.HelloTests testExample]' passed (0.264 seconds). Test Suite 'HelloTests' passed at 2018-08-28 11:23:17.019. Executed 1 test, with 0 failures (0 unexpected) in 0.264 (0.264) seconds Test Suite 'HelloPackageTests.xctest' passed at 2018-08-28 11:23:17.019. Executed 1 test, with 0 failures (0 unexpected) in 0.264 (0.264) seconds Test Suite 'All tests' passed at 2018-08-28 11:23:17.019. Executed 1 test, with 0 failures (0 unexpected) in 0.264 (0.264) seconds
1、创建文件夹,并进入文件夹
$ mkdir HelloExcutable $ cd HelloExcutable/
2、初始化一个名为Hello的可执行文件
$ swift package init --type executable
会生成以下的文件结构
HelloExcutable的目录结构
3、运行HelloExcutable
$ swift run HelloExcutable Compile Swift Module 'HelloExcutable' (1 sources) Linking ./.build/x86_64-apple-macosx10.10/debug/HelloExcutable Hello, world!
4、Build HelloExcutable
$ swift build
会在当前目录创建一个.build的文件夹,里面是编译后的内容。
编译后的目录结构
可以看到在x86_64-apple-macosx10.10/debug文件夹里有一个HelloExcutable的可执行文件。
5、直接运行HelloExcutable
$ .build/x86_64-apple-macosx10.10/debug/HelloExcutable
6、多个xxx.swift的情况: 在HelloExcutable(和Main.swift同级)的目录下创建名为Greeter.swift的文件,在里面插入代码:
func sayHello(name: String) { print("Hello, \(name)!") }
修改Main.swift:
if CommandLine.arguments.count != 2 { print("Usage: hello NAME") } else { let name = CommandLine.arguments[1] sayHello(name: name) }
7、运行来查看效果
$ swift run HelloExcutable `whoami` Compile Swift Module 'HelloExcutable' (2 sources) Linking /Users/leacode/Documents/Swift/HelloExcutable/.build/x86_64-apple-macosx10.10/debug/HelloExcutable Hello, leacode!
会获得命令行的结果,并打印出来
执行命令
$ swift package init --help OVERVIEW: Initialize a new package OPTIONS: --type empty|library|executable|system-module
可以看到目前SwiftPM支持四种类型,指定不同的type可以创建不同类型的项目。由于swift支持不同的平台,所以创建项目的时候并没有生成xcode文件,如果是在非Mac平台开发,可以使用其他IDE进行开发,如果在Mac上开发就会方便很多,可以使用以下命令创建xcodeproj文件:
$ swift package generate-xcodeproj
执行命令
$ swift build --help OVERVIEW: Build sources into binary products USAGE: swift build [options] OPTIONS: --build-path Specify build/cache directory [default: ./.build] --build-tests Build both source and test targets --configuration, -c Build with configuration (debug|release) [default: debug] --disable-prefetching --disable-sandbox Disable using the sandbox when executing subprocesses --enable-build-manifest-caching Enable llbuild manifest caching [Experimental] --no-static-swift-stdlib Do not link Swift stdlib statically --package-path Change working directory before any other operation --product Build the specified product --show-bin-path Print the binary output path --static-swift-stdlib Link Swift stdlib statically --target Build the specified target --verbose, -v Increase verbosity of informational output -Xcc Pass flag through to all C compiler invocations -Xcxx Pass flag through to all C++ compiler invocations -Xlinker Pass flag through to all linker invocations -Xswiftc Pass flag through to all Swift compiler invocations --help Display available options
可以看到build项目除了直接用build命令之外还可以加上一些额外的选项。这里做一下讲解
USAGE: swift build [options] OPTIONS: --build-path 指定编译文件存放的路径(默认路径是./.build) --build-tests 编译源码和测试代码 --configuration, -c 编译环境(debug|release),默认是debug --disable-prefetching 禁止prefetching --disable-sandbox 禁用沙盒 --enable-build-manifest-caching 打开llbuild清单缓存(实验功能,这个就是增量编译了) --no-static-swift-stdlib 不要静态link Swift stdlib --package-path 当自己指定源代码路径的时候使用此命令 --product 编译指定的product --show-bin-path 打印二进制文件输出路径 --static-swift-stdlib 静态link Swift stdlib --target 编译特定的target --verbose, -v Increase verbosity of informational output -Xcc 将标志传递给所有C编译器调用 -Xcxx 将标志传递给所有C++编译器调用 -Xlinker 将标志传递给所有linker调用 -Xswiftc 将标志传递给所有Swift编译器调用 --help 查看帮助
如果你只是一个swift开发人员,指定路径、指定环境是工作中会最常用到的命令。
执行命令
$ swift run --help OVERVIEW: Build and run an executable product USAGE: swift run [options] [executable [arguments ...]] OPTIONS: --build-path Specify build/cache directory [default: ./.build] --configuration, -c Build with configuration (debug|release) [default: debug] --disable-prefetching --disable-sandbox Disable using the sandbox when executing subprocesses --enable-build-manifest-caching Enable llbuild manifest caching [Experimental] --no-static-swift-stdlib Do not link Swift stdlib statically --package-path Change working directory before any other operation --skip-build Skip building the executable product --static-swift-stdlib Link Swift stdlib statically --verbose, -v Increase verbosity of informational output -Xcc Pass flag through to all C compiler invocations -Xcxx Pass flag through to all C++ compiler invocations -Xlinker Pass flag through to all linker invocations -Xswiftc Pass flag through to all Swift compiler invocations --help Display available options POSITIONAL ARGUMENTS: executable The executable to run
和上面的build一样,在运行项目的时候,可以配置不同的环境参数来运行不同的target或环境
通过SwiftPM创建项目的时候会在项目的根目录生成一个Package.swift的文件,这个文件就相当于cocoapods的Podfile 或者Carthage 的Cartfile.
首先来看看 HelloExcutable 这个项目的Package.swift文件:
// swift-tools-version:4.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "HelloExcutable", 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 which this package depends on. .target( name: "HelloExcutable", dependencies: []), ] )
目前这个项目没有添加任何依赖,添加依赖的步骤如下:
1、引入一个依赖库SwiftNIO
import PackageDescription let package = Package( name: "HelloExcutable", dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", from: "1.9.2") ], targets: [ .target( name: "HelloExcutable", dependencies: ["NIO", "NIOHTTP1", "NIOFoundationCompat"]), ] )
2、执行命令
swift build
这时候会下载依赖的package,下载完后会编译项目。
3、重新生成 xcodeproj文件(仅Mac适用)
swift package generate-xcodeproj
打开生成的 HelloExcutable.xcodeproj 文件就可以看到刚刚添加的依赖已经集成到项目里了:
添加dependencies之后的项目
Package.swift是用于管理项目依赖以及项目结构的文件,文件内容就是一个 Package 类的实例。
这里是Package这个Class的init方法:
final public class Package { ... public init(name: String, //项目的名称 pkgConfig: String? = default, providers: [PackageDescription.SystemPackageProvider]? = default, products: [PackageDescription.Product] = default, // 对外公开的产物 dependencies: [PackageDescription.Package.Dependency] = default, // 依赖 targets: [PackageDescription.Target] = default, // 项目的targets swiftLanguageVersions: [Int]? = default, // swift版本 cLanguageStandard: PackageDescription.CLanguageStandard? = default, // c语言标准 cxxLanguageStandard: PackageDescription.CXXLanguageStandard? = default) // c++语言标准 }
可以根据项目的需要,设置对应的参数。 比如要用SwiftPM做一个framework,那么需要设置products指定Framework的名字和target。
当项目中需要添加依赖的时候,需要设置dependencies参数, 是一个Package.Dependency类的集合,下面是Package.Dependency的部分源码:
extension Package.Dependency : Equatable { public static func package(url: String, from version: PackageDescription.Version) -> PackageDescription.Package.Dependency public static func package(url: String, _ requirement: PackageDescription.Package.Dependency.Requirement) -> PackageDescription.Package.Dependency public static func package(url: String, _ range: Range<PackageDescription.Version>) -> PackageDescription.Package.Dependency public static func package(url: String, _ range: ClosedRange<PackageDescription.Version>) -> PackageDescription.Package.Dependency ... }
类似cocoapods 和 Carthage, Package.Dependency有两个参数,第一个参数设置依赖库的url,第二个参数设置依赖库的版本
设置版本的语法:
.package(url:"", from: "1.0.0") (1.0.0 ..< 2.0.0) .package(url:"", from: "1.2.0") (1.2.0 ..< 2.0.0) .package(url:"", from: "1.5.8") (1.5.8 ..< 2.0.0) .package(url:"", .exactItem(Version(stringLiteral: "1.2.0")) (==1.2.0) .package(url:"", .exactItem(Version(stringLiteral: "1.2.0")) (==1.2.0) .package(url:"", .revisionItem("74663ec")) 某次提交的revision的值 .package(url:"", .branchItem("develop")) 分支名 .package(url:"", .localPackageItem) 本地依赖 .package(url:"", Version(stringLiteral: "1.2.3")...Version(stringLiteral: "1.2.8")) (>=1.2.3 && <=1.2.8) .package(url:"", Version(stringLiteral: "1.2.3")..<Version(stringLiteral: "1.2.8")) (>=1.2.3 && <1.2.8)
同样上面的Version也可以用以下方式来写:
Version(1, 2, 0) 相当于于 Version(stringLiteral: "1.2.0") Version(1, 0, 0)..<Version(1, .max, .max) 意思是版本大于1.0.0 小于2.0.0
另外一个比较重要的类是Target:
final public class Package { ... public static func target(name: String, // target的名称 dependencies: [PackageDescription.Target.Dependency] = default, // target 的依赖,这里面主要指定Package添加的依赖的module的名字 path: String? = default, // target的路径,如果自定义文件夹需要设置此参数 exclude: [String] = default, // target path中不希望被包含的path sources: [String]? = default, // 资源文件的路径 publicHeadersPath: String? = default // 公共header文件的路径 ) -> PackageDescription.Target ... }
用于定义项目里的target。
本篇主要介绍了SwiftPM的一些基础用法,使用时需要注意以下几点:
1、dependencies里面的链接和版本一定要写对,target里的dependencies对应的总的dependencies中的module,一个依赖可以有多个module。
2、注意多个库依赖时的兼容性,如果出现卡着不动的时候,常常是依赖的版本有问题,可以逐步添加来排查问题。
3、Package.swift中的语法不要写错,注意 [ ]和 ""要成对存在,不要漏了前后的符号。
4、如果你不是在Mac上开发,可以使用Atom等支持高亮的编辑器来编辑Package.swift文件。
5、不要去尝试用它来管理iOS项目的依赖,现在还不支持,到支持的时候我会更新此文章。
希望本文能给你带来一些帮助,有疑问或者需要补充的地方欢迎留言。
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句