Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift Package Manager

Swift Package Manager

Overview talk on the Swift Package Manager, given at Tokyo iOS Meetup, March 2016.

Boris Bügling

March 05, 2016

More Decks by Boris Bügling

Other Decks in Programming


  1. Agenda • What is swiftpm? • Making our own package

    • How does it work? • Comparison with related tools
  2. import PackageDescription let package = Package( name: "Hello", dependencies: [

    .Package(url: "ssh://[email protected]/Greeter.git", versions: Version(1,0,0)..<Version(2,0,0)), ] )
  3. What does it do? • Compiles and links Swift packages

    • Resolves, fetches and builds their dependencies
  4. Current state • Currently builds static libraries or binaries •

    Supported platforms are OS X and Ubuntu Linux • Only builds Swift code, no C/C++/Objective-C/...
  5. $ swift build --help OVERVIEW: Build sources into binary products

    USAGE: swift build [options] MODES: --configuration <value> Build with configuration (debug|release) [-c] --clean Delete all build intermediaries and products [-k] OPTIONS: --chdir <value> Change working directory before any other operation [-C] -v Increase verbosity of informational output
  6. Spectre describe("a person") { let person = Person(name: "Kyle") $0.it("has

    a name") { try expect(person.name) == "Kyle" } $0.it("returns the name as description") { try expect(person.description) == "Kyle" } }
  7. spectre-build $ swift build $ .build/debug/spectre-build -> a person ->

    has a name -> returns the name as description 2 passes and 0 failures
  8. import PackageDescription let package = Package( name: "Clock", testDependencies: [

    .Package(url: "https://github.com/neonichu/spectre-build.git", majorVersion: 0), ] )
  9. $ make test swift build ./.build/debug/spectre-build -> Converting dates to

    strings -> can convert NSDate to an ISO8601 GMT string -> Parsing of localtime dates -> can parse dates -> can parse dates with negative timezone offsets -> can parse timezone offsets without colons -> Parsing of UTC dates -> can parse dates -> can parse epoch -> can parse dates without seconds -> is resilient against Y2K bugs 8 passes and 0 failures
  10. Travis CI os: - linux - osx language: generic sudo:

    required dist: trusty osx_image: xcode7.2 install: - curl -sL https://gist.github.com/kylef/ 5c0475ff02b7c7671d2a/raw/ 621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash script: - . ~/.swiftenv/init
  11. public func parse_package(packagePath: String) throws -> PackageDescription.Package { // FIXME:

    We depend on `chswift` installation and use here let toolchainPath = PathKit.Path(POSIX.getenv("CHSWIFT_TOOLCHAIN") ?? "") libc.setenv("SPM_INSTALL_PATH", toolchainPath.parent().description, 1) print_if("Using libPath \(Resources.runtimeLibPath)", false) let package = (try Manifest(path: packagePath)).package print_if("Converting package \(package.name) at \(packagePath)", false) return package }
  12. Foundation is incomplete and sometimes different from OS X: #if

    os(Linux) let index = p.startIndex.distanceTo(p.startIndex.successor()) path = NSString(string: p).substringFromIndex(index) #else path = p.substringFromIndex(p.startIndex.successor()) #endif
  13. Some things in the standard library might not be available:

    #if _runtime(_ObjC) // Excluded due to use of dynamic casting and Builtin.autorelease, neither // of which correctly work without the ObjC Runtime right now. // See rdar://problem/18801510 [...] public func getVaList(args: [CVarArgType]) -> CVaListPointer {
  14. OS X libc and Glibc can differ: let flags =

    GLOB_TILDE | GLOB_BRACE | GLOB_MARK if system_glob(cPattern, flags, nil, &gt) == 0 { #if os(Linux) let matchc = gt.gl_pathc #else let matchc = gt.gl_matchc #endif
  15. And other random fun: ./.build/debug/spectre-build /usr/bin/ld: .build/debug/Clock.a(ISO8601Parser.swift.o): undefined reference to

    symbol '_swift_FORCE_LOAD_$_swiftGlibc' /home/travis/.swiftenv/versions/swift-2.2-SNAPSHOT-2015-12-22-a/ usr/lib/swift/linux/libswiftGlibc.so: error adding symbols: DSO missing from command line clang: error: linker command failed with exit code 1 (use -v to see invocation)
  16. Integrate system libraries • Empty Package.swift • module.modulemap: module curl

    [system] { header "/usr/include/curl/curl.h" link "curl" export * }
  17. Modules inside SwiftPackageManager • OS abstractions: libc, POSIX, sys •

    Package: PackageDescription • Manifest: dep • Downloading code: swift-get • Building code: swift-build
  18. Dependencies • Can be local or remote Git repositories •

    Need to be tagged • Will be fetched to ./Packages/MyPackage-0.0.1
  19. Rough build process • PackageDescription generates TOML • dep parses

    the TOML and can generate YAML • Dependencies are fetched by swift-get • YAML is used as input to llbuild • swift-build calls out to llbuild
  20. commands: <Clock-swiftc>: tool: swift-compiler executable: "/usr/bin/swiftc" inputs: ["ISO8601Parser.swift","ISO8601Writer.swift"] outputs: ["<Clock-swiftc>","Clock.swiftmodule",

    "ISO8601Parser.swift.o","ISO8601Writer.swift.o"] module-name: "Clock" module-output-path: "Clock.swiftmodule" is-library: true sources: ["ISO8601Parser.swift","ISO8601Writer.swift"] objects: ["ISO8601Parser.swift.o","ISO8601Writer.swift.o"] import-paths: ["/Users/boris/Projects/Clock/.build/debug"] temps-path: "/Users/boris/Projects/Clock/.build/debug/Clock.o/Clock" other-args: ["-j8","-Onone","-g","-target","x86_64-apple-macosx10.10", "-enable-testing","-sdk", "/.../Developer/SDKs/MacOSX10.11.sdk","-I","/usr/local/include"]
  21. <Clock>: tool: shell inputs: ["<Clock-swiftc>","ISO8601Parser.swift.o","ISO8601Writer.swift.o"] outputs: ["<Clock>","Clock.a"] args: ["/bin/sh","-c","rm -f

    'Clock.a'; ar cr 'Clock.a' 'ISO8601Parser.swift.o' 'ISO8601Writer.swift.o'"] description: "Linking Library: .build/debug/Clock.a"
  22. Targets import PackageDescription let package = Package( name: "Example", targets:

    [ Target( name: "top", dependencies: [.Target(name: "bottom")]), Target( name: "bottom") ] )
  23. Test dependencies import PackageDescription let package = Package( name: "Hello",

    testDependencies: [ .Package(url: "ssh://[email protected]/Tester.git", versions: Version(1,0,0)..<Version(2,0,0)), ] )
  24. Customizing builds import PackageDescription var package = Package() #if os(Linux)

    let target = Target(name: "LinuxSources/foo") package.targets.append(target) #endif
  25. CocoaPods • Centralized discovery • Xcode integration • Support for

    other languages • Additional metadata in the Manifest • Does not cover the build process
  26. !

  27. You should think of it as an alpha code base

    that hasn't had a release yet. Yes, it is useful for doing some things [...] — Daniel Dunbar
  28. References • https://swift.org • https://github.com/apple/swift-package-manager • https://github.com/apple/llbuild • https://github.com/neonichu/chocolat •

    https://github.com/neonichu/chswift • https://github.com/neonichu/freedom • https://github.com/kylef/spectre-build