# Caching SwiftPM for iOS app build on CI env

**URL:** <https://forums.swift.org/t/caching-swiftpm-for-ios-app-build-on-ci-env/39122>\
**Category:** Using Swift\
**Tags:** ios, swiftpm\
**Created:** [August 6, 2020, 12:31pm UTC](https://forums.swift.org/t/caching-swiftpm-for-ios-app-build-on-ci-env/39122 "2020-08-06T12:31:10Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![sharplet](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sharplet/32/6184_2.png) [@sharplet](https://forums.swift.org/u/sharplet)\
**Post date:** [August 6, 2020, 2:15pm UTC](https://forums.swift.org/t/caching-swiftpm-for-ios-app-build-on-ci-env/39122/2 "2020-08-06T14:15:35Z")

</div>

I know SwiftPM folks such as @Aciid and @ddunbar are working towards deterministic builds & caching in the future. The [llbuild2 project](https://forums.swift.org/t/llbuild2/36896) is one such effort.

In the meantime, I'm currently implementing a basic caching strategy based on a checksum of the Swift source file contents. The basic idea is to introduce a shell script that wraps `swift run` and explicitly passes `--skip-build` if the checksum has not changed.

```bash
#!/bin/sh
#
# bin/run: Wraps swift-run and provides caching.
#
# Usage:
#
# bin/run <executable-product> [<args>...] # wraps 'swift run' to run an executable product
# bin/run --build # run 'swift build' if the cache is invalid
# bin/run --clean # run 'swift package clean' and invalidate the cache
# bin/run --resolve # run 'swift package resolve'
# bin/run --update [<dependency>] # run 'swift package update', optionally for a specific dependency
# bin/run --shasum # print out the current cache key

set -e

cache_key() {
  cat Package.resolved {Sources,.build/checkouts}/**/*.swift \
    | shasum \
    | cut -f1 -d' '
}

cache_valid() {
  ["$IGNORE_CACHE" != 1] \
    && [-f "$SWIFTPM_CACHE_KEY_PATH"] \
    && ["$(cat "$SWIFTPM_CACHE_KEY_PATH")" = "$(cache_key)"]
}

write_cache_key() {
  if [-n "$SWIFTPM_CACHE_KEY_PATH"]; then
    mkdir -p "$(dirname "$SWIFTPM_CACHE_KEY_PATH")"
    cache_key > "$SWIFTPM_CACHE_KEY_PATH"
  fi
}

# wrap the system swift binary to set some defaults
swift() {
  env SDKROOT=macosx swift "$@"
}

build_if_necessary() {
  if ! cache_valid; then
    swift build
    write_cache_key
  fi
}

# set up a default value for SWIFTPM_CACHE_KEY_PATH which stores
# the cache key inside .build
if [-z ${SWIFTPM_CACHE_KEY_PATH+x}]; then
  export SWIFTPM_CACHE_KEY_PATH=.build/contents.sha
fi

if [$# = 0]; then
  echo >&2 "bin/run: Specify a subcommand to run."
  exit 1
fi

case "$1" in
  --build)
    build_if_necessary
    ;;
  --clean)
    swift package clean
    ;;
  --resolve)
    swift package resolve
    ;;
  --update)
    shift
    swift package update "$@"
    ;;
  --shasum)
    cache_key
    ;;
  *)
    build_if_necessary
    swift run --skip-build "$@"
    ;;
esac

```

---

_[View the full topic](https://forums.swift.org/t/caching-swiftpm-for-ios-app-build-on-ci-env/39122)._
