             }
             addNode(targetOutput, toTarget: .test)
         }
-
+    }
+
+    private func addModuleWrapCmd(_ target: SwiftTargetBuildDescription) {
         // 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)
-        }
+        guard buildParameters.debuggingStrategy == .modulewrap else { return }
+        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
    ) {
        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
                }
            }
        }

        let cmdName = target.target.getCommandName(config: buildConfig)
        let cmdOutputs = target.objects.map(Node.file) + [.file(target.moduleOutputPath)]

        let isLibrary = target.target.type == .library || target.target.type == .test
        manifest.addSwiftCmd(
            name: cmdName,
            inputs: inputs,

            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)
