diff --git a/Sources/SWBCore/DependencyResolution.swift b/Sources/SWBCore/DependencyResolution.swift index 3316db1b..ccad7d11 100644 --- a/Sources/SWBCore/DependencyResolution.swift +++ b/Sources/SWBCore/DependencyResolution.swift @@ -623,26 +623,20 @@ extension SpecializationParameters { /// Determines whether a target should be configured for the given platform in the index arena. /// - /// The arena is used for two purposes: - /// 1. To retrieve settings for a given target - /// 2. To produce products of source dependencies for compilation purposes (it does not produce binaries) + /// When building a workspace build description, we configure for all possible platforms. As such, + /// we want to avoid unnecessarily configuring targets for unsupported platforms. When building a + /// target or package description, we are only configuring for a single platform and can therefore + /// avoid this check since we assume any dependency will necessary. /// - /// Thus, in general if a target doesn't support a platform, we don't want to configure it for that platform. If a - /// dependency is not supported for the platform of the dependent, presumably the dependent will not be able - /// to use its products for compilation purposes, since the source products will be put in a different platform - /// directory and/or they will not be usable by the dependent (e.g. the module will not be importable from a - /// different platform). If the dependency was intended to be usable from that platform for compilation purposes, - /// it would be a supported platform. - /// - /// There's an exception for this for a dependent host tool, which are required for compilation and must therefore - /// be configured (and registered as a dependency) regardless. - nonisolated func isTargetSuitableForPlatformForIndex(_ target: Target, parameters: BuildParameters, imposedParameters: SpecializationParameters?, dependencies: OrderedSet? = nil) -> Bool { - if !buildRequest.enableIndexBuildArena { - return true - } - - // Host tools case, always supported we'll override the parameters with that of the host regardless. - if target.isHostBuildTool || dependencies?.contains(where: { $0.target.isHostBuildTool }) == true { + /// Note there's an exception for this for host build tools, which are required for compilation + /// and must therefore be configured (and registered as a dependency) regardless + nonisolated func isTargetSuitableForPlatformForIndex(_ target: Target, parameters: BuildParameters, imposedParameters: SpecializationParameters?) -> Bool { + guard buildRequest.buildsIndexWorkspaceDescription else { return true } + + // Host tools case, always supported since we'll override the parameters with that of the + // host regardless. Any dependencies will have the host platform imposed on them through + // `imposedParameters`. + if target.isHostBuildTool { return true } diff --git a/Sources/SWBCore/LinkageDependencyResolver.swift b/Sources/SWBCore/LinkageDependencyResolver.swift index e5b9fcd0..9c648201 100644 --- a/Sources/SWBCore/LinkageDependencyResolver.swift +++ b/Sources/SWBCore/LinkageDependencyResolver.swift @@ -122,8 +122,7 @@ actor LinkageDependencyResolver { if Task.isCancelled { return } let configuredTarget = topLevelTargetsToDiscover[i] let imposedParameters = resolver.specializationParameters(configuredTarget, workspaceContext: workspaceContext, buildRequest: buildRequest, buildRequestContext: buildRequestContext) - let dependenciesOnPath = LinkageDependencies() - await linkageDependencies(for: configuredTarget, imposedParameters: imposedParameters, dependenciesOnPath: dependenciesOnPath) + await linkageDependencies(for: configuredTarget, imposedParameters: imposedParameters) } } @@ -141,7 +140,7 @@ actor LinkageDependencyResolver { private var dependenciesPerTarget = [ConfiguredTarget: [ResolvedTargetDependency]]() private var visitedDiscoveredTargets = Set() - private func linkageDependencies(for configuredTarget: ConfiguredTarget, imposedParameters: SpecializationParameters?, dependenciesOnPath: LinkageDependencies) async { + private func linkageDependencies(for configuredTarget: ConfiguredTarget, imposedParameters: SpecializationParameters?) async { // Track that we have visited this target. let visited = !visitedDiscoveredTargets.insert(configuredTarget).inserted @@ -167,7 +166,7 @@ actor LinkageDependencyResolver { return nil } let buildParameters = resolver.buildParametersByTarget[target] ?? configuredTarget.parameters - if await !resolver.isTargetSuitableForPlatformForIndex(target, parameters: buildParameters, imposedParameters: imposedParameters, dependencies: dependenciesOnPath.path) { + if await !resolver.isTargetSuitableForPlatformForIndex(target, parameters: buildParameters, imposedParameters: imposedParameters) { return nil } let effectiveImposedParameters = imposedParameters?.effectiveParameters(target: configuredTarget, dependency: ConfiguredTarget(parameters: buildParameters, target: target), dependencyResolver: resolver) @@ -195,7 +194,7 @@ actor LinkageDependencyResolver { } else { imposedParametersForDependency = resolver.specializationParameters(dependency.target, workspaceContext: workspaceContext, buildRequest: buildRequest, buildRequestContext: buildRequestContext) } - await self.linkageDependencies(for: dependency.target, imposedParameters: imposedParametersForDependency, dependenciesOnPath: dependenciesOnPath) + await self.linkageDependencies(for: dependency.target, imposedParameters: imposedParametersForDependency) } } @@ -657,7 +656,3 @@ private extension Path { return basenameWithoutSuffix.nilIfEmpty } } - -fileprivate actor LinkageDependencies { - var path: OrderedSet = [] -} diff --git a/Sources/SWBCore/TargetDependencyResolver.swift b/Sources/SWBCore/TargetDependencyResolver.swift index 018abdc2..e1f85acb 100644 --- a/Sources/SWBCore/TargetDependencyResolver.swift +++ b/Sources/SWBCore/TargetDependencyResolver.swift @@ -680,7 +680,7 @@ fileprivate extension TargetDependencyResolver { } // Add the discovered info. - let discoveredInfo = await computeDiscoveredTargetInfo(for: configuredTarget, imposedParameters: imposedParameters, dependencyPath: nil, resolver: resolver) + let discoveredInfo = await computeDiscoveredTargetInfo(for: configuredTarget, imposedParameters: imposedParameters, resolver: resolver) discoveredTargets[configuredTarget] = discoveredInfo // If we have no dependencies, we are done. @@ -742,7 +742,7 @@ fileprivate extension TargetDependencyResolver { discoveredInfo = info } else { if resolver.makeAggregateTargetsTransparentForSpecialization { - discoveredInfo = await computeDiscoveredTargetInfo(for: configuredTarget, imposedParameters: imposedParameters, dependencyPath: dependencyPath, resolver: resolver) + discoveredInfo = await computeDiscoveredTargetInfo(for: configuredTarget, imposedParameters: imposedParameters, resolver: resolver) } else { var immediateDependencies = [ResolvedTargetDependency]() var packageProductDependencies = [PackageProductTarget]() @@ -820,14 +820,14 @@ fileprivate extension TargetDependencyResolver { } /// Discover the info for a configured target with the given imposed parameters. - private func computeDiscoveredTargetInfo(for configuredTarget: ConfiguredTarget, imposedParameters: SpecializationParameters?, dependencyPath: OrderedSet?, resolver: isolated DependencyResolver) async -> DiscoveredTargetInfo { + private func computeDiscoveredTargetInfo(for configuredTarget: ConfiguredTarget, imposedParameters: SpecializationParameters?, resolver: isolated DependencyResolver) async -> DiscoveredTargetInfo { var immediateDependencies = [ResolvedTargetDependency]() var packageProductDependencies = [PackageProductTarget]() for dependency in resolver.explicitDependencies(for: configuredTarget) { if let asPackageProduct = dependency as? PackageProductTarget { packageProductDependencies.append(asPackageProduct) } else { - if !resolver.isTargetSuitableForPlatformForIndex(dependency, parameters: configuredTarget.parameters, imposedParameters: imposedParameters, dependencies: dependencyPath) { + if !resolver.isTargetSuitableForPlatformForIndex(dependency, parameters: configuredTarget.parameters, imposedParameters: imposedParameters) { continue } diff --git a/Sources/SWBTestSupport/BuildOperationTester.swift b/Sources/SWBTestSupport/BuildOperationTester.swift index 5294b027..17c93778 100644 --- a/Sources/SWBTestSupport/BuildOperationTester.swift +++ b/Sources/SWBTestSupport/BuildOperationTester.swift @@ -1553,6 +1553,7 @@ package final class BuildOperationTester { /// Construct 'prepare' index build operation, and test the result. package func checkIndexBuild( prepareTargets: [String], + buildTargets: [any TestTarget]? = nil, workspaceOperation: Bool = true, runDestination: RunDestinationInfo? = nil, persistent: Bool = false, @@ -1561,6 +1562,7 @@ package final class BuildOperationTester { ) async throws -> T { let buildRequest = try Self.buildRequestForIndexOperation( workspace: workspace, + buildTargets: buildTargets, prepareTargets: prepareTargets, workspaceOperation: workspaceOperation, runDestination: runDestination, diff --git a/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift b/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift index 1e4748d3..689bf872 100644 --- a/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/HostBuildToolBuildOperationTests.swift @@ -158,198 +158,119 @@ fileprivate struct HostBuildToolBuildOperationTests: CoreBasedTests { } } - @Test(.requireSDKs(.macOS)) - func hostToolsAndDependenciesAreBuiltDuringIndexingPreparation_Mac() async throws { - try await testHostToolsAndDependenciesAreBuiltDuringIndexingPreparation(destination: .anyMac) - } - - @Test(.requireSDKs(.macOS, .iOS)) - func hostToolsAndDependenciesAreBuiltDuringIndexingPreparation_MacCatalyst() async throws { - try await testHostToolsAndDependenciesAreBuiltDuringIndexingPreparation(destination: .anyMacCatalyst) - } - - @Test(.requireSDKs(.macOS, .iOS)) - func hostToolsAndDependenciesAreBuiltDuringIndexingPreparation_iOS() async throws { - try await testHostToolsAndDependenciesAreBuiltDuringIndexingPreparation(destination: .anyiOSDevice) - } - - func testHostToolsAndDependenciesAreBuiltDuringIndexingPreparation(destination: RunDestinationInfo) async throws { - try await withTemporaryDirectory { tmpDirPath async throws -> Void in - let depPackage = try await TestPackageProject( - "DepPackage", - groupTree: TestGroup("Foo", children: [ - TestFile("transitivedep.swift"), - TestFile("dep.swift"), - ]), - buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SWIFT_VERSION": swiftVersion, - "GENERATE_INFOPLIST_FILE": "YES", - "PRODUCT_NAME": "$(TARGET_NAME)", - "CODE_SIGNING_ALLOWED": "NO", - ]), - ], - targets: [ - TestStandardTarget("TransitivePackageDep", type: .objectFile, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ], - impartedBuildProperties: - TestImpartedBuildProperties( - buildSettings: [ - "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "IMPARTED_SETTINGS" - ]) - ), - ], buildPhases: [ - TestSourcesBuildPhase(["transitivedep.swift"]) + private func withHostToolsPackages( + clients: TestProject..., + body: (BuildOperationTester, TestWorkspace) async throws -> Void + ) async throws { + let depPackage = try await TestPackageProject( + "DepPackage", + groupTree: TestGroup("Foo", children: [ + TestFile("transitivedep.swift"), + TestFile("dep.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)", ]), - TestStandardTarget("PackageDep", type: .staticLibrary, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["dep.swift"]), - TestFrameworksBuildPhase([ - TestBuildFile(.target("TransitivePackageDep")) - ]) - ], dependencies: [ - "TransitivePackageDep" - ]), - TestPackageProductTarget("PackageDepProduct", frameworksBuildPhase: - TestFrameworksBuildPhase([ - TestBuildFile(.target("PackageDep")), - ] - ), buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], dependencies: [ - "PackageDep" - ]), - ]) - - let hostToolsPackage = try await TestPackageProject( - "HostToolsPackage", - groupTree: TestGroup("Foo", children: [ - TestFile("tool.swift"), - TestFile("lib.swift"), - ]), - buildConfigurations: [ + ], + targets: [ + TestStandardTarget("TransitivePackageDep", type: .objectFile, buildConfigurations: [ TestBuildConfiguration( "Debug", - buildSettings: [ - "SWIFT_VERSION": swiftVersion, - "GENERATE_INFOPLIST_FILE": "YES", - "PRODUCT_NAME": "$(TARGET_NAME)", - "CODE_SIGNING_ALLOWED": "NO", - ]), - ], - targets: [ - TestStandardTarget("HostTool", type: .hostBuildTool, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - ]) - ], buildPhases: [ - TestSourcesBuildPhase(["tool.swift"]), - TestFrameworksBuildPhase([TestBuildFile(.target("PackageDepProduct"))]) - ], dependencies: [ - "PackageDepProduct" - ]), - TestStandardTarget("HostToolClientLib", type: .objectFile, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["lib.swift"]), - ], dependencies: [ - "HostTool" + buildSettings: [:], + impartedBuildProperties: + TestImpartedBuildProperties( + buildSettings: [ + "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "IMPARTED_SETTINGS" + ]) + ), + ], buildPhases: [ + TestSourcesBuildPhase(["transitivedep.swift"]) + ]), + TestStandardTarget("PackageDep", type: .staticLibrary, buildPhases: [ + TestSourcesBuildPhase(["dep.swift"]), + TestFrameworksBuildPhase([ + TestBuildFile(.target("TransitivePackageDep")) + ]) + ], dependencies: [ + "TransitivePackageDep" + ]), + TestPackageProductTarget("PackageDepProduct", frameworksBuildPhase: + TestFrameworksBuildPhase([ + TestBuildFile(.target("PackageDep")), + ] + ), dependencies: [ + "PackageDep" + ]), + ]) + + let hostToolsPackage = try await TestPackageProject( + "HostToolsPackage", + groupTree: TestGroup("Foo", children: [ + TestFile("tooldep.swift"), + TestFile("tool.swift"), + TestFile("lib.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)", ]), - TestPackageProductTarget("HostToolClientLibProduct", frameworksBuildPhase: - TestFrameworksBuildPhase([TestBuildFile(.target("HostToolClientLib"))] - ), buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], dependencies: [ - "HostToolClientLib" + ], + targets: [ + TestStandardTarget("HostToolDep", type: .objectFile, buildPhases: [ + TestSourcesBuildPhase(["tooldep.swift"]), + ]), + TestStandardTarget("HostTool", type: .hostBuildTool, buildPhases: [ + TestSourcesBuildPhase(["tool.swift"]), + TestFrameworksBuildPhase([ + TestBuildFile(.target("PackageDepProduct")), + TestBuildFile(.target("HostToolDep")), ]), - ]) + ], dependencies: [ + "PackageDepProduct", + "HostToolDep", + ]), + TestStandardTarget("HostToolClientLib", type: .objectFile, buildPhases: [ + TestSourcesBuildPhase(["lib.swift"]), + ], dependencies: [ + "HostTool" + ]), + TestPackageProductTarget("HostToolClientLibProduct", frameworksBuildPhase: + TestFrameworksBuildPhase([TestBuildFile(.target("HostToolClientLib"))] + ), dependencies: [ + "HostToolClientLib" + ]), + ]) - let testProject = try await TestProject( - "aProject", - groupTree: TestGroup("Foo", children: [ - TestFile("frame.swift"), - TestFile("app.swift") - ]), buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SWIFT_VERSION": swiftVersion, - "GENERATE_INFOPLIST_FILE": "YES", - "PRODUCT_NAME": "$(TARGET_NAME)", - "CODE_SIGNING_ALLOWED": "NO", - ]), - ], - targets: [ - TestStandardTarget("Framework", type: .framework, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["frame.swift"]), - TestFrameworksBuildPhase([ - TestBuildFile(.target("HostToolClientLibProduct")) - ]), - ], dependencies: [ - "HostToolClientLibProduct" - ]), - TestStandardTarget("App", type: .application, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["app.swift"]), - ], dependencies: [ - "Framework" - ]), - ] - ) - let testWorkspace = TestWorkspace("aWorkspace", sourceRoot: tmpDirPath.join("Test"), projects: [depPackage, hostToolsPackage, testProject]) + try await withTemporaryDirectory { tmpDirPath in + let testWorkspace = TestWorkspace("aWorkspace", sourceRoot: tmpDirPath.join("Test"), projects: [depPackage, hostToolsPackage] + clients) let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false, systemInfo: .init(operatingSystemVersion: Version(99, 98, 97), productBuildVersion: "99A98", nativeArchitecture: Architecture.host.stringValue ?? "undefined_arch")) - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/transitivedep.swift")) { stream in + let fs = tester.fs + let root = testWorkspace.sourceRoot + + try await fs.writeFileContents(root.join("DepPackage/transitivedep.swift")) { stream in stream <<< """ public let transitiveDependencyMessage = "Hello from host tool transitive dependency!" """ } - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/dep.swift")) { stream in + try await fs.writeFileContents(root.join("DepPackage/dep.swift")) { stream in stream <<< """ import TransitivePackageDep @@ -361,26 +282,87 @@ fileprivate struct HostBuildToolBuildOperationTests: CoreBasedTests { """ } - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/tool.swift")) { stream in + try await fs.writeFileContents(root.join("HostToolsPackage/tooldep.swift")) { stream in + stream <<< + """ + public let samePackageMsg = "Hello from host tool same-package dependency!" + """ + } + + try await fs.writeFileContents(root.join("HostToolsPackage/tool.swift")) { stream in stream <<< """ import PackageDep + import HostToolDep @main struct Foo { static func main() { - print("Hello from host tool! " + dependencyMessage) + print("Hello from host tool! " + dependencyMessage + samePackageMsg) } } """ } - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/lib.swift")) { stream in + try await fs.writeFileContents(root.join("HostToolsPackage/lib.swift")) { stream in stream <<< """ public class MyClass {} """ } + try await body(tester, testWorkspace) + } + } + + @Test(.requireSDKs(.macOS, .iOS), arguments: [RunDestinationInfo.anyMac, .anyMacCatalyst, .anyiOSDevice]) + func testHostToolsAndDependenciesAreBuiltDuringIndexingPreparation(destination: RunDestinationInfo) async throws { + let testProject = try await TestProject( + "aProject", + groupTree: TestGroup("Foo", children: [ + TestFile("frame.swift"), + TestFile("app.swift") + ]), buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + ]), + ], + targets: [ + TestStandardTarget("Framework", type: .framework, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], buildPhases: [ + TestSourcesBuildPhase(["frame.swift"]), + TestFrameworksBuildPhase([ + TestBuildFile(.target("HostToolClientLibProduct")) + ]), + ], dependencies: [ + "HostToolClientLibProduct" + ]), + TestStandardTarget("App", type: .application, buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", + ]), + ], buildPhases: [ + TestSourcesBuildPhase(["app.swift"]), + ], dependencies: [ + "Framework" + ]), + ] + ) + + try await withHostToolsPackages(clients: testProject) { tester, testWorkspace in try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("aProject/frame.swift")) { stream in stream <<< """ @@ -439,176 +421,57 @@ fileprivate struct HostBuildToolBuildOperationTests: CoreBasedTests { } } - @Test(.requireSDKs(.macOS)) - func testHostToolsAndDependenciesAreBuiltDuringIndexingPreparationForPackage() async throws { - try await withTemporaryDirectory { tmpDirPath async throws -> Void in - let depPackage = try await TestPackageProject( - "DepPackage", - groupTree: TestGroup("Foo", children: [ - TestFile("transitivedep.swift"), - TestFile("dep.swift"), - ]), - buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SWIFT_VERSION": swiftVersion, - "GENERATE_INFOPLIST_FILE": "YES", - "PRODUCT_NAME": "$(TARGET_NAME)", - "CODE_SIGNING_ALLOWED": "NO", - ]), - ], - targets: [ - TestStandardTarget("TransitivePackageDep", type: .objectFile, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ], - impartedBuildProperties: - TestImpartedBuildProperties( - buildSettings: [ - "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "IMPARTED_SETTINGS" - ]) - ), - ], buildPhases: [ - TestSourcesBuildPhase(["transitivedep.swift"]) + @Test(.requireSDKs(.macOS, .iOS), arguments: [RunDestinationInfo.anyMac, .anyMacCatalyst, .anyiOSDevice], [true, false]) + func testHostToolsAndDependenciesAreBuiltDuringIndexingPreparationForPackage( + destination: RunDestinationInfo, targetBuild: Bool + ) async throws { + let clientPackage = try await TestPackageProject( + "ClientPackage", + groupTree: TestGroup("Client", children: [ + TestFile("main.swift"), + ]), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SWIFT_VERSION": swiftVersion, + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGNING_ALLOWED": "NO", + "SDKROOT": "auto", + "SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)", ]), - TestStandardTarget("PackageDep", type: .staticLibrary, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["dep.swift"]), - TestFrameworksBuildPhase([ - TestBuildFile(.target("TransitivePackageDep")) - ]) - ], dependencies: [ - "TransitivePackageDep" - ]), - TestPackageProductTarget("PackageDepProduct", frameworksBuildPhase: - TestFrameworksBuildPhase([ - TestBuildFile(.target("PackageDep")), - ] - ), buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], dependencies: [ - "PackageDep" - ]), - ]) - - let hostToolsPackage = try await TestPackageProject( - "HostToolsPackage", - groupTree: TestGroup("Foo", children: [ - TestFile("tool.swift"), - TestFile("lib.swift"), + ], + targets: [ + TestStandardTarget("HostToolClient", type: .objectFile, buildPhases: [ + TestSourcesBuildPhase(["main.swift"]), + TestFrameworksBuildPhase([TestBuildFile(.target("HostToolClientLibProduct"))]), + ], dependencies: [ + "HostToolClientLibProduct" ]), - buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SWIFT_VERSION": swiftVersion, - "GENERATE_INFOPLIST_FILE": "YES", - "PRODUCT_NAME": "$(TARGET_NAME)", - "CODE_SIGNING_ALLOWED": "NO", - ]), - ], - targets: [ - TestStandardTarget("HostTool", type: .hostBuildTool, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - ]) - ], buildPhases: [ - TestSourcesBuildPhase(["tool.swift"]), - TestFrameworksBuildPhase([TestBuildFile(.target("PackageDepProduct"))]) - ], dependencies: [ - "PackageDepProduct" - ]), - TestStandardTarget("HostToolClientLib", type: .objectFile, buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], buildPhases: [ - TestSourcesBuildPhase(["lib.swift"]), - ], dependencies: [ - "HostTool" - ]), - TestPackageProductTarget("HostToolClientLibProduct", frameworksBuildPhase: - TestFrameworksBuildPhase([TestBuildFile(.target("HostToolClientLib"))] - ), buildConfigurations: [ - TestBuildConfiguration( - "Debug", - buildSettings: [ - "SDKROOT": "auto", - "SUPPORTED_PLATFORMS": "macosx iphoneos iphonesimulator", - ]), - ], dependencies: [ - "HostToolClientLib" - ]), - ]) - - let testWorkspace = TestWorkspace("aWorkspace", sourceRoot: tmpDirPath.join("Test"), projects: [depPackage, hostToolsPackage]) - let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false, systemInfo: .init(operatingSystemVersion: Version(99, 98, 97), productBuildVersion: "99A98", nativeArchitecture: Architecture.host.stringValue ?? "undefined_arch")) - - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/transitivedep.swift")) { stream in - stream <<< - """ - public let transitiveDependencyMessage = "Hello from host tool transitive dependency!" - """ - } + ]) - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("DepPackage/dep.swift")) { stream in + try await withHostToolsPackages(clients: clientPackage) { tester, testWorkspace in + try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("ClientPackage/main.swift")) { stream in stream <<< """ - import TransitivePackageDep - - public let dependencyMessage = "Hello from host tool dependency! " + transitiveDependencyMessage - #if !IMPARTED_SETTINGS - #error("settings not imparted") - #endif - """ - } - - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/tool.swift")) { stream in - stream <<< - """ - import PackageDep - - @main struct Foo { - static func main() { - print("Hello from host tool! " + dependencyMessage) - } - } - """ - } - - try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("HostToolsPackage/lib.swift")) { stream in - stream <<< - """ - public class MyClass {} + print("Hello, world!") """ } - try await tester.checkIndexBuild(prepareTargets: hostToolsPackage.targets.map(\.guid), workspaceOperation: false, runDestination: .anyMac, persistent: true) { results in + let clientTarget = try #require(clientPackage.targets.first) + try await tester.checkIndexBuild( + prepareTargets: [clientTarget.guid], + buildTargets: targetBuild ? [clientTarget] : nil, + workspaceOperation: false, runDestination: destination, + persistent: true + ) { results in results.checkNoDiagnostics() results.checkTaskExists(.matchTargetName("HostTool"), .matchRuleType("Ld")) try results.checkTask(.matchTargetName("HostTool"), .matchRuleType(ProductPlan.preparedForIndexPreCompilationRuleName)) { task in try results.checkTaskFollows(task, .matchTargetName("PackageDep"), .matchRuleType("Libtool")) + try results.checkTaskFollows(task, .matchTargetName("HostToolDep"), .matchRuleType("SwiftDriver Compilation")) } } } diff --git a/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift b/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift index c787f3f7..72009cc8 100644 --- a/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift +++ b/Tests/SWBCoreTests/IndexTargetDependencyResolverTests.swift @@ -949,8 +949,12 @@ import SWBUtil #expect(results.targets(packageProduct).map{ results.targetNameAndPlatform($0) } == ["PackageLibProduct-iphoneos"]) #expect(results.targets(unreferencedPackageLib).map{ results.targetNameAndPlatform($0) } == ["UnreferencedPackageLib-iphoneos"]) - try results.checkDependencies(of: .init(packageLib2, "iphoneos"), are: []) - + switch results.graphType { + case .dependency: + try results.checkDependencies(of: packageLib2, are: [.init(packageTool, "macos")]) + case .linkage: + try results.checkDependencies(of: packageLib2, are: []) + } results.delegate.checkNoDiagnostics() } }