Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion Sources/SWBTaskConstruction/ProductPlanning/ProductPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
package import SWBUtil
package import SWBCore
import SWBMacro
import SWBProtocol
package import SWBProtocol
import Foundation

/// The `GlobalProductPlanDelegate` is a subset of the more ubiquitous `TaskPlanningDelegate` which provides functionality only needed by a `GlobalProductPlan`, even if it exists outside the context of a build.
Expand Down Expand Up @@ -109,6 +109,25 @@ package final class GlobalProductPlan: GlobalTargetInfoProvider
resolvedDependencies(of: target).map { $0.target }
}

package var targetDependenciesByGuid: [TargetDependencyRelationship] {
allTargets.map { target in
.init(
.init(
name: target.target.name,
guid: target.guid.stringValue
),
dependencies: resolvedDependencies(of: target).map {
.init(
name: $0.target.target.name,
guid: $0.target.guid.stringValue
)
}
.sorted(by: \.guid)
)
}
.sorted(by: \.target.guid)
}

package func resolvedDependencies(of target: ConfiguredTarget) -> [ResolvedTargetDependency] {
// Use the static target for lookup if necessary.
let configuredTarget: ConfiguredTarget
Expand Down
33 changes: 31 additions & 2 deletions Sources/SWBTaskExecution/BuildDescriptionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ package final class BuildDescriptionManager: Sendable {

let definingTargetsByModuleName = {
var definingTargetsByModuleName: [String: OrderedSet<ConfiguredTarget>] = [:]
for target in buildGraph.allTargets {
for target in plan.globalProductPlan.allTargets {
let settings = plan.globalProductPlan.getTargetSettings(target)
let moduleInfo = plan.globalProductPlan.getModuleInfo(target)
let specLookupContext = SpecLookupCtxt(specRegistry: planRequest.workspaceContext.core.specRegistry, platform: settings.platform)
Expand All @@ -265,7 +265,36 @@ package final class BuildDescriptionManager: Sendable {
}()

// Create the build description.
return try await BuildDescription.construct(workspace: planRequest.workspaceContext.workspace, tasks: plan.tasks, path: path, signature: signature, buildCommand: planRequest.buildRequest.buildCommand, diagnostics: planningDiagnostics, indexingInfo: [], fs: fs, bypassActualTasks: bypassActualTasks, targetsBuildInParallel: buildGraph.targetsBuildInParallel, emitFrontendCommandLines: plan.emitFrontendCommandLines, moduleSessionFilePath: planRequest.workspaceContext.getModuleSessionFilePath(planRequest.buildRequest.parameters), invalidationPaths: plan.invalidationPaths, recursiveSearchPathResults: plan.recursiveSearchPathResults, copiedPathMap: plan.copiedPathMap, rootPathsPerTarget: rootPathsPerTarget, moduleCachePathsPerTarget: moduleCachePathsPerTarget, artifactInfoPerTarget: artifactInfoPerTarget, casValidationInfos: casValidationInfos.values, staleFileRemovalIdentifierPerTarget: staleFileRemovalIdentifierPerTarget, settingsPerTarget: settingsPerTarget, delegate: delegate, targetDependencies: buildGraph.targetDependenciesByGuid, definingTargetsByModuleName: definingTargetsByModuleName, userPreferences: planRequest.workspaceContext.userPreferences)
return try await BuildDescription.construct(
workspace: planRequest.workspaceContext.workspace,
tasks: plan.tasks,
path: path,
signature: signature,
buildCommand: planRequest.buildRequest.buildCommand,
diagnostics: planningDiagnostics,
indexingInfo: [],
fs: fs,
bypassActualTasks: bypassActualTasks,
targetsBuildInParallel: buildGraph.targetsBuildInParallel,
emitFrontendCommandLines: plan.emitFrontendCommandLines,
moduleSessionFilePath: planRequest.workspaceContext
.getModuleSessionFilePath(
planRequest.buildRequest.parameters
),
invalidationPaths: plan.invalidationPaths,
recursiveSearchPathResults: plan.recursiveSearchPathResults,
copiedPathMap: plan.copiedPathMap,
rootPathsPerTarget: rootPathsPerTarget,
moduleCachePathsPerTarget: moduleCachePathsPerTarget,
artifactInfoPerTarget: artifactInfoPerTarget,
casValidationInfos: casValidationInfos.values,
staleFileRemovalIdentifierPerTarget: staleFileRemovalIdentifierPerTarget,
settingsPerTarget: settingsPerTarget,
delegate: delegate,
targetDependencies: plan.globalProductPlan.targetDependenciesByGuid,
definingTargetsByModuleName: definingTargetsByModuleName,
userPreferences: planRequest.workspaceContext.userPreferences
)
}

/// Encapsulates the two ways `getNewOrCachedBuildDescription` can be called, whether we want to retrieve or create a build description based on a plan or whether we have an explicit build description ID that we want to retrieve and we don't need to create a new one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,167 @@ fileprivate struct DiscoveredDependenciesBuildOperationTests: CoreBasedTests {
}
}

@Test(.requireSDKs(.macOS))
func doesNotDiagnoseMissingTargetDependenciesForDynamicTargetVariants() async throws {
try await withTemporaryDirectory { tmpDirPath async throws -> Void in
let swiftVersionValue = try await swiftVersion
let testWorkspace = TestWorkspace(
"Test",
sourceRoot: tmpDirPath.join("Test"),
projects: [
TestProject(
"AppProject",
groupTree: TestGroup("Sources"),
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"CODE_SIGNING_ALLOWED": "NO",
"PRODUCT_NAME": "$(TARGET_NAME)",
"SDKROOT": "macosx",
"SWIFT_VERSION": swiftVersionValue,
]
),
],
targets: [
TestStandardTarget(
"App",
type: .framework,
buildPhases: [
TestFrameworksBuildPhase([
TestBuildFile(.target("macOSFwk")),
TestBuildFile(.target("PackageLibProduct2")),
]),
],
dependencies: [
"macOSFwk",
"PackageLibProduct2",
]
),
TestStandardTarget(
"macOSFwk",
type: .framework,
buildPhases: [
TestFrameworksBuildPhase([
TestBuildFile(.target("PackageLibProduct")),
]),
],
dependencies: ["PackageLibProduct"]
),
]
),
TestPackageProject(
"Modules",
groupTree: TestGroup(
"Sources", path: "Sources", children: [
TestFile("Common.swift"),
TestFile("Core.swift"),
]),
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"ALWAYS_SEARCH_USER_PATHS": "NO",
"DIAGNOSE_MISSING_TARGET_DEPENDENCIES": "YES",
"PRODUCT_NAME": "$(TARGET_NAME)",
"SDKROOT": "auto",
"SDK_VARIANT": "auto",
"SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)",
"SWIFT_VERSION": swiftVersionValue,
]
),
],
targets: [
TestPackageProductTarget(
"PackageLibProduct",
frameworksBuildPhase: TestFrameworksBuildPhase([
TestBuildFile(.target("Common")),
]),
dependencies: ["Common"]
),
TestPackageProductTarget(
"PackageLibProduct2",
frameworksBuildPhase: TestFrameworksBuildPhase([
TestBuildFile(.target("Common")),
]),
dependencies: ["Common"]
),
TestStandardTarget(
"Common",
type: .objectFile,
buildPhases: [TestSourcesBuildPhase(["Common.swift"])],
dependencies: ["Core"],
dynamicTargetVariantName: "Common-dynamic"
),
TestStandardTarget(
"Common-dynamic",
type: .framework,
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"PRODUCT_NAME": "Common",
"SDKROOT": "auto",
"SDK_VARIANT": "auto",
"SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)",
"SWIFT_MODULE_NAME": "Common",
"SWIFT_VERSION": swiftVersionValue,
]
),
],
buildPhases: [
TestSourcesBuildPhase(["Common.swift"]),
TestFrameworksBuildPhase([
TestBuildFile(.target("Core")),
]),
],
dependencies: ["Core"]
),
TestStandardTarget(
"Core",
type: .objectFile,
buildPhases: [TestSourcesBuildPhase(["Core.swift"])],
dynamicTargetVariantName: "Core-dynamic"
),
TestStandardTarget(
"Core-dynamic",
type: .framework,
buildConfigurations: [
TestBuildConfiguration(
"Debug",
buildSettings: [
"PRODUCT_NAME": "Core",
"SDKROOT": "auto",
"SDK_VARIANT": "auto",
"SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)",
"SWIFT_MODULE_NAME": "Core",
"SWIFT_VERSION": swiftVersionValue,
]
),
],
buildPhases: [TestSourcesBuildPhase(["Core.swift"])]
),
]
),
]
)
let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false)
let packageSourceRoot = testWorkspace.sourceRoot.join("Modules/Sources")

try await tester.fs.writeFileContents(packageSourceRoot.join("Common.swift")) { contents in
contents <<< "import Core\n"
contents <<< "public func commonValue() -> String { coreValue() }\n"
}
try await tester.fs.writeFileContents(packageSourceRoot.join("Core.swift")) { contents in
contents <<< "public func coreValue() -> String { \"core\" }\n"
}

try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug"), runDestination: .macOS) { results in
results.checkNoDiagnostics()
}
}
}

// This tests checks for a very particular sequence of actions that lead to a cyclical dependency error. The gist of
// it is that <rdar://59011589> clang incorrectly adds the module it is building for as a dependency through an
// LC_LINKER_OPTION. This leads to the linker linking a binary against itself, which is propagated to llbuild
Expand Down
Loading