How does "swift build" cache builds?

I have this weird situation where I have a script spec, which does this:

#!/bin/bash

set -o pipefail && swift test "$@" 2>&1 | xcpretty -s && swiftlint --quiet

I usually use this to run tests because the output is nicer. However, sometimes there are issues where xcpretty hides too many details, so I have to run swift test to get all the output (e.g. log statements).

However, I observe the following behaviour:

  • When I run ./spec several times without changing the code, it only needs to compile the code the first time
  • The same thing happens when I run swift test several times
  • However, if I run ./spec and then swift test, or the other way around, it somehow needs to recompile everything (even all the dependencies). This happens every time I switch between the two commands: apparently Swift doesn't keep a separate cache for ./spec and for swift test, but it just destroys the cache for one command every time I run the other command.

What could be the reason for this behaviour, and is there any way to avoid this? My project takes a long time to compile from scratch, so it would be really nice if this didn't happen.

1 Like

I too would be interested to know how build caching works. I use syntastic with vim but it’s very slow because it recompiles everything on each build.

When you pipe the output, the compiler arguments change (I think it’s just colour diagnostics right now) and llbuild thinks it needs to recompile everything. This is a bug in SwiftPM and it needs to ignore that flag when computing the signature of Swift tasks. I think you can avoid hitting this bug by making SwiftPM think that it’s in a dumb terminal.

interesting, do you have more details on that (especially about the workaround)?

Try executing vanilla swift test with this variable: TERM=dumb

1 Like

that seems to help. :+1:
has this bug already been logged?

Yep: [SR-7982] Swift build forces recompilation with Makefile · Issue #5353 · apple/swift-package-manager · GitHub