             WMO: buildParameters.configuration == .release
         )
 
+        addTargetCmd(target, cmdOutputs: cmdOutputs)
+        addModuleWrapCmd(target)
+    }
+
+    private func computeSwiftCompileCmdInputs(
+        _ target: SwiftTargetBuildDescription
+    ) -> [Node] {
+        var inputs = target.sources.map(Node.file)
+
+        // Add resources node as the input to the target. This isn't great because we
+        // don't need to block building of a module until its resources are assembled but
+        // we don't currently have a good way to express that resources should be built
+        // whenever a module is being built.
+        if let resourcesNode = createResourcesBundle(for: .swift(target)) {
+            inputs.append(resourcesNode)
+        }
+
+        func addStaticTargetInputs(_ target: ResolvedTarget) {
+            // Ignore C Modules.
+            if target.underlyingTarget is SystemLibraryTarget { return }
+
+            // Depend on the binary for executable targets.
+            if target.type == .executable {
+                // FIXME: Optimize.
+                let _product = plan.graph.allProducts.first {
+                    $0.type == .executable && $0.executableModule == target
+                }
+                if let product = _product {
+                    inputs.append(file: plan.productMap[product]!.binary)
+                }
+                return
+            }
+
+            switch plan.targetMap[target] {
+            case .swift(let target)?:
+                inputs.append(file: target.moduleOutputPath)
+            case .clang(let target)?:
+                for object in target.objects {
+                    inputs.append(file: object)
+                }
+            case nil:
+                fatalError("unexpected: target \(target) not in target map \(plan.targetMap)")
+            }
+        }
+
+        for dependency in target.target.dependencies {
+            switch dependency {
+            case .target(let target):
+                addStaticTargetInputs(target)
+
+            case .product(let product):
+                switch product.type {
+                case .executable, .library(.dynamic):
+                    // Establish a dependency on binary of the product.
+                    inputs.append(file: plan.productMap[product]!.binary)
+
+                // For automatic and static libraries, add their targets as static input.
+                case .library(.automatic), .library(.static):
+                    for target in product.targets {
+                        addStaticTargetInputs(target)
+                    }
+
+                case .test:
+                    break
+                }
+            }
+        }
+
+        return inputs
+    }
+
+    /// Adds a top-level phony command that builds the entire target.
+    private func addTargetCmd(_ target: SwiftTargetBuildDescription, cmdOutputs: [Node]) {
         // Create a phony node to represent the entire target.
         let targetName = target.target.getLLBuildTargetName(config: buildConfig)
         let targetOutput: Node = .virtual(targetName)

            }
            addNode(targetOutput, toTarget: .test)
        }

        // Add commands to perform the module wrapping Swift modules when debugging statergy is `modulewrap`.
        if buildParameters.debuggingStrategy == .modulewrap {
            let moduleWrapArgs = [
                target.buildParameters.toolchain.swiftCompiler.pathString,
                "-modulewrap", target.moduleOutputPath.pathString,
                "-o", target.wrappedModuleOutputPath.pathString
            ]
            manifest.addShellCmd(
                name: target.wrappedModuleOutputPath.pathString,
                description: "Wrapping AST for \(target.target.name) for debugging",
                inputs: [.file(target.moduleOutputPath)],
                outputs: [.file(target.wrappedModuleOutputPath)],
                args: moduleWrapArgs)
        }
    }
}


    private func createSwiftCompileCommand(
        _ target: SwiftTargetBuildDescription
    ) {
        let inputs = computeSwiftCompileCmdInputs(target)

        let cmdName = target.target.getCommandName(config: buildConfig)
        let objectNodes = target.objects.map(Node.file)
        let moduleNode = Node.file(target.moduleOutputPath)
        let cmdOutputs = objectNodes + [moduleNode]
        let isLibrary = target.target.type == .library || target.target.type == .test

        manifest.addSwiftCmd(
            name: cmdName,
            inputs: inputs,
