Skip to content

SwiftPM tries to build _everything_ instead of just what is needed for swift test or swift build --product XYZ #9272

@ephemer

Description

@ephemer

Is it reproducible with SwiftPM command-line tools: swift build, swift test, swift package etc?

  • Confirmed reproduction steps with SwiftPM CLI. The description text must include reproduction steps with either of command-line SwiftPM commands, swift build, swift test, swift package etc.

Description

swift test tries to build all targets, instead of just those needed to build and run the tests that exist.

The reason this is important to us: we have a Swift Package containing a core library (that we want to test), and then numerous other dynamic library and executable targets that use the core library, but often on esoteric platforms like postgresql, as a python plugin, etc.

To build the esoteric Products we need to provide specific build invocations with multiple flags, header search paths, etc. We can’t put (all of) those flags into Package.swift specific to those targets, because they require unsafe flags, which from my understanding would make our package unconsumable from other packages, including our own. While we could put header search paths into Package.swift, this is not portable for things like homebrew dependencies – we need to get them on the fly per dev/per machine.

Building too many targets is also bad for performance. A directly related issue: SwiftPM might build for an arbitrary amount of time before even realising that there are no test targets at all. This seems entirely avoidable.

Expected behavior

To solve the entire issue (and significantly improve build speeds in some cases), SwiftPM should treat our testTarget as a separate product, and build (only!) that product and its dependencies.

That said, all of the above also applies to swift build --product XYZ: instead of just building the targets required for XYZ, SwiftPM tries to build everything.

Indeed, in the Swift Package we're trying to test, we do have a separate product for just the core library – swift build --product OurCoreLibrary doesn't work either for the same reasons (SwiftPM tries to build the esoteric targets even though no-one is asking for them in this moment).

Actual behavior

% swift test
[1/1] Planning build
Building for debugging...
In file included from Sources/CWhatever/include/CWhatever.h:7:10: fatal error: 'some_irrelevant_header.h' file not found
    7 | #include <some_irrelevant_header.h>
      |          ^~~~~~~~~~~~~
1 error generated.
[0/9] Write swift-version--535765D8E7DB8D2F.txt
error: fatalError

Using swiftbuild doesn't help. Also, SwiftPM builds everything before even realising that there is no test target at all – this is the same issue manifesting differently:

% swift test --build-system=swiftbuild
Building for debugging...
[97/100] Math 139 / 142
[100/100]
Build complete! (9,22 sec.)
error: no tests found; create a target in the 'Tests' directory

Steps to reproduce

  1. swift package init
  2. Add a target that is not a dependency of the default testTarget, or of the default product, but is a (direct or indirect) dependency of another product. Fake a build error in it #error whatever.
  3. swift test, and/or swift build --product TheOneWithoutTheBrokenTarget – boom.

You can test this yourself by cloning https://github.com/ephemer/TestPM and following the readme.

Swift Package Manager version/commit hash

Swift Package Manager - Swift 6.2.0-dev

Swift & OS version (output of swift --version ; uname -a)

swift --version
Apple Swift version 6.2 (swift-6.2-RELEASE)
Target: arm64-apple-macosx26.0
Build config: +assertions
uname -a
Darwin MyMachine.local 25.0.0 Darwin Kernel Version 25.0.0: Wed Sep 17 21:35:32 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T6020 arm64

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions