@@ -128,6 +128,9 @@ public struct BuildParameters {
128
128
/// Whether to enable code coverage.
129
129
public let enableCodeCoverage : Bool
130
130
131
+ /// Whether to enable test discovery on platforms without Objective-C runtime.
132
+ public let enableTestDiscovery : Bool
133
+
131
134
/// Whether to enable generation of `.swiftinterface` files alongside
132
135
/// `.swiftmodule`s.
133
136
public let enableParseableModuleInterfaces : Bool
@@ -156,7 +159,8 @@ public struct BuildParameters {
156
159
sanitizers: EnabledSanitizers = EnabledSanitizers ( ) ,
157
160
enableCodeCoverage: Bool = false ,
158
161
indexStoreMode: IndexStoreMode = . auto,
159
- enableParseableModuleInterfaces: Bool = false
162
+ enableParseableModuleInterfaces: Bool = false ,
163
+ enableTestDiscovery: Bool = false
160
164
) {
161
165
self . dataPath = dataPath
162
166
self . configuration = configuration
@@ -170,6 +174,7 @@ public struct BuildParameters {
170
174
self . enableCodeCoverage = enableCodeCoverage
171
175
self . indexStoreMode = indexStoreMode
172
176
self . enableParseableModuleInterfaces = enableParseableModuleInterfaces
177
+ self . enableTestDiscovery = enableTestDiscovery
173
178
}
174
179
175
180
/// Returns the compiler arguments for the index store, if enabled.
@@ -469,13 +474,22 @@ public final class SwiftTargetBuildDescription {
469
474
/// If this target is a test target.
470
475
public let isTestTarget : Bool
471
476
477
+ /// True if this is the test discovery target.
478
+ public let testDiscoveryTarget : Bool
479
+
472
480
/// Create a new target description with target and build parameters.
473
- init ( target: ResolvedTarget , buildParameters: BuildParameters , isTestTarget: Bool ? = nil ) {
481
+ init (
482
+ target: ResolvedTarget ,
483
+ buildParameters: BuildParameters ,
484
+ isTestTarget: Bool ? = nil ,
485
+ testDiscoveryTarget: Bool = false
486
+ ) {
474
487
assert ( target. underlyingTarget is SwiftTarget , " underlying target type mismatch \( target) " )
475
488
self . target = target
476
489
self . buildParameters = buildParameters
477
490
// Unless mentioned explicitly, use the target type to determine if this is a test target.
478
491
self . isTestTarget = isTestTarget ?? ( target. type == . test)
492
+ self . testDiscoveryTarget = testDiscoveryTarget
479
493
}
480
494
481
495
/// The arguments needed to compile this target.
@@ -868,6 +882,65 @@ public class BuildPlan {
868
882
/// Diagnostics Engine for emitting diagnostics.
869
883
let diagnostics : DiagnosticsEngine
870
884
885
+ private static func planLinuxMain(
886
+ _ buildParameters: BuildParameters ,
887
+ _ graph: PackageGraph
888
+ ) throws -> ( ResolvedTarget , SwiftTargetBuildDescription ) ? {
889
+ guard buildParameters. triple. isLinux ( ) else {
890
+ return nil
891
+ }
892
+
893
+ // Currently, there can be only one test product in a package graph.
894
+ guard let testProduct = graph. allProducts. first ( where: { $0. type == . test } ) else {
895
+ return nil
896
+ }
897
+
898
+ if !buildParameters. enableTestDiscovery {
899
+ guard let linuxMainTarget = testProduct. linuxMainTarget else {
900
+ throw Error . missingLinuxMain
901
+ }
902
+
903
+ let desc = SwiftTargetBuildDescription (
904
+ target: linuxMainTarget,
905
+ buildParameters: buildParameters,
906
+ isTestTarget: true
907
+ )
908
+ return ( linuxMainTarget, desc)
909
+ }
910
+
911
+ // We'll generate sources containing the test names as part of the build process.
912
+ let derivedTestListDir = buildParameters. buildPath. appending ( components: " testlist.derived " )
913
+ let mainFile = derivedTestListDir. appending ( component: " main.swift " )
914
+
915
+ var paths : [ AbsolutePath ] = [ ]
916
+ paths. append ( mainFile)
917
+ let testTargets = graph. rootPackages. flatMap { $0. targets } . filter { $0. type == . test }
918
+ for testTarget in testTargets {
919
+ let path = derivedTestListDir. appending ( components: testTarget. name + " .swift " )
920
+ paths. append ( path)
921
+ }
922
+
923
+ let src = Sources ( paths: paths, root: derivedTestListDir)
924
+
925
+ let swiftTarget = SwiftTarget (
926
+ testDiscoverySrc: src,
927
+ name: testProduct. name,
928
+ dependencies: testProduct. underlyingProduct. targets)
929
+ let linuxMainTarget = ResolvedTarget (
930
+ target: swiftTarget,
931
+ dependencies: testProduct. targets. map ( ResolvedTarget . Dependency. target)
932
+ )
933
+
934
+ let target = SwiftTargetBuildDescription (
935
+ target: linuxMainTarget,
936
+ buildParameters: buildParameters,
937
+ isTestTarget: true ,
938
+ testDiscoveryTarget: true
939
+ )
940
+
941
+ return ( linuxMainTarget, target)
942
+ }
943
+
871
944
/// Create a build plan with build parameters and a package graph.
872
945
public init (
873
946
buildParameters: BuildParameters ,
@@ -921,19 +994,10 @@ public class BuildPlan {
921
994
throw Diagnostics . fatalError
922
995
}
923
996
924
- if buildParameters. triple. isLinux ( ) {
925
- // FIXME: Create a target for LinuxMain file on linux.
926
- // This will go away once it is possible to auto detect tests.
927
- let testProducts = graph. allProducts. filter ( { $0. type == . test } )
928
-
929
- for product in testProducts {
930
- guard let linuxMainTarget = product. linuxMainTarget else {
931
- throw Error . missingLinuxMain
932
- }
933
- let target = SwiftTargetBuildDescription (
934
- target: linuxMainTarget, buildParameters: buildParameters, isTestTarget: true )
935
- targetMap [ linuxMainTarget] = . swift( target)
936
- }
997
+ // Plan the linux main target.
998
+ if let result = try Self . planLinuxMain ( buildParameters, graph) {
999
+ targetMap [ result. 0 ] = . swift( result. 1 )
1000
+ self . linuxMainTarget = result. 0
937
1001
}
938
1002
939
1003
var productMap : [ ResolvedProduct : ProductBuildDescription ] = [ : ]
@@ -953,6 +1017,8 @@ public class BuildPlan {
953
1017
try plan ( )
954
1018
}
955
1019
1020
+ private var linuxMainTarget : ResolvedTarget ?
1021
+
956
1022
static func validateDeploymentVersionOfProductDependency(
957
1023
_ product: ResolvedProduct ,
958
1024
forTarget target: ResolvedTarget ,
@@ -1094,7 +1160,7 @@ public class BuildPlan {
1094
1160
1095
1161
if buildParameters. triple. isLinux ( ) {
1096
1162
if product. type == . test {
1097
- product . linuxMainTarget. map ( { staticTargets. append ( $0) } )
1163
+ linuxMainTarget. map ( { staticTargets. append ( $0) } )
1098
1164
}
1099
1165
}
1100
1166
0 commit comments