-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
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
swift package init
- 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
. swift test
, and/orswift 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