From ad1edc2153e58c76caf2c76c927e03f2bb21188d Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 17 Apr 2024 21:27:51 +0100 Subject: [PATCH 01/14] Revert "Revert "Support macros when cross-compiling (#7118)" (#7352)" (#7353) Reverts apple/swift-package-manager#7352. Modified to build tests for the host triple when any macros are added to test modules directly as dependencies. (cherry picked from commit cb3b0856f3616e9a505c94d2c7958b83ab32f9f6) # Conflicts: # CHANGELOG.md # Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift # Sources/Build/BuildManifest/LLBuildManifestBuilder.swift # Sources/Build/BuildPlan/BuildPlan.swift # Sources/Commands/SwiftTestCommand.swift # Sources/Commands/Utilities/PluginDelegate.swift # Sources/Commands/Utilities/TestingSupport.swift # Sources/PackageGraph/ModulesGraph+Loading.swift # Sources/PackageGraph/ModulesGraph.swift # Sources/SPMTestSupport/MockBuildTestHelper.swift # Sources/SPMTestSupport/MockPackageGraphs.swift # Sources/SPMTestSupport/PackageGraphTester.swift # Sources/SPMTestSupport/ResolvedTarget+Mock.swift # Tests/BuildTests/ClangTargetBuildDescriptionTests.swift # Tests/BuildTests/CrossCompilationBuildPlanTests.swift # Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift --- CHANGELOG.md | 7 +- .../Basics/Collections/IdentifiableSet.swift | 11 +- .../ClangTargetBuildDescription.swift | 6 +- .../ProductBuildDescription.swift | 4 +- .../ResolvedModule+BuildDescription.swift | 23 +++ .../SwiftTargetBuildDescription.swift | 132 ++++++++------- .../TargetBuildDescription.swift | 2 +- .../LLBuildManifestBuilder+Clang.swift | 2 +- .../LLBuildManifestBuilder+Product.swift | 6 +- .../LLBuildManifestBuilder+Swift.swift | 36 ++-- .../LLBuildManifestBuilder.swift | 28 ++-- Sources/Build/BuildOperation.swift | 34 ++-- .../Build/BuildPlan/BuildPlan+Product.swift | 12 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 4 +- Sources/Build/BuildPlan/BuildPlan+Test.swift | 61 ++++--- Sources/Build/BuildPlan/BuildPlan.swift | 79 +++++---- Sources/Build/CMakeLists.txt | 1 + .../PackageCommands/PluginCommand.swift | 11 +- .../Utilities/SymbolGraphExtract.swift | 2 +- .../Commands/Utilities/TestingSupport.swift | 11 +- Sources/Commands/Utilities/XCTEvents.swift | 18 +- Sources/PackageGraph/BuildTriple.swift | 23 +++ Sources/PackageGraph/CMakeLists.txt | 2 +- .../PackageGraph/ModulesGraph+Loading.swift | 24 ++- Sources/PackageGraph/ModulesGraph.swift | 80 +++++++-- ...olvedTarget.swift => ResolvedModule.swift} | 59 ++++++- .../Resolution/ResolvedPackage.swift | 2 +- .../Resolution/ResolvedProduct.swift | 58 ++++++- Sources/PackageModel/Target/Target.swift | 2 +- .../BuildParameters/BuildParameters.swift | 10 +- .../BuildSystem/BuildSystem.swift | 2 +- .../Plugins/PluginContextSerializer.swift | 2 +- .../Plugins/PluginInvocation.swift | 12 +- Sources/SPMTestSupport/MockArchiver.swift | 2 +- .../SPMTestSupport/MockBuildTestHelper.swift | 58 ++++--- .../SPMTestSupport/MockPackageGraphs.swift | 147 +++++++++++++++-- .../SPMTestSupport/PackageGraphTester.swift | 132 +++++++++++---- .../SPMTestSupport/ResolvedTarget+Mock.swift | 10 +- Tests/BuildTests/BuildOperationTests.swift | 8 +- Tests/BuildTests/BuildPlanTests.swift | 115 +++++++------ .../ClangTargetBuildDescriptionTests.swift | 25 ++- .../CrossCompilationBuildPlanTests.swift | 143 +++++++++++++++- .../LLBuildManifestBuilderTests.swift | 58 +++++-- .../BuildTests/ModuleAliasingBuildTests.swift | 26 +-- Tests/BuildTests/PluginsBuildPlanTests.swift | 24 ++- .../ProductBuildDescriptionTests.swift | 2 +- Tests/CommandsTests/PackageCommandTests.swift | 47 ++++-- .../SwiftCommandStateTests.swift | 8 +- .../PackageGraphPerfTests.swift | 4 +- .../CrossCompilationPackageGraphTests.swift | 156 ++++++++++++++++++ .../ResolvedTargetTests.swift | 68 ++++---- .../PluginInvocationTests.swift | 25 +-- .../SourceKitLSPAPITests.swift | 31 +++- 53 files changed, 1393 insertions(+), 462 deletions(-) create mode 100644 Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift rename Sources/PackageGraph/Resolution/{ResolvedTarget.swift => ResolvedModule.swift} (78%) create mode 100644 Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 823b4e423de..e97c318d52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,13 +27,18 @@ Swift 6.0 `// swift-tools-version:` can now be specified on subsequent lines of `Package.swift`, for example when first few lines are required to contain a licensing comment header. +* [#7118] + + Macros cross-compiled by SwiftPM with Swift SDKs are now correctly built, loaded, and evaluated for the host triple. + Swift 5.10 ----------- + * [#7010] On macOS, `swift build` and `swift run` now produce binaries that allow backtraces in debug builds. Pass `SWIFT_BACKTRACE=enable=yes` environment variable to enable backtraces on such binaries when running them. -* [7101] +* [#7101] Binary artifacts are now cached along side repository checkouts so they do not need to be re-downloaded across projects. diff --git a/Sources/Basics/Collections/IdentifiableSet.swift b/Sources/Basics/Collections/IdentifiableSet.swift index c1007329e53..46383085b2b 100644 --- a/Sources/Basics/Collections/IdentifiableSet.swift +++ b/Sources/Basics/Collections/IdentifiableSet.swift @@ -47,13 +47,22 @@ public struct IdentifiableSet: Collection { } public subscript(id: Element.ID) -> Element? { - self.storage[id] + get { + self.storage[id] + } + set { + self.storage[id] = newValue + } } public func index(after i: Index) -> Index { Index(storageIndex: self.storage.elements.index(after: i.storageIndex)) } + public mutating func insert(_ element: Element) { + self.storage[element.id] = element + } + public func union(_ otherSequence: some Sequence) -> Self { var result = self for element in otherSequence { diff --git a/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift b/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift index e821ffa2331..5c68bc5c2d5 100644 --- a/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift @@ -53,7 +53,7 @@ public final class ClangTargetBuildDescription { /// Path to the bundle generated for this module (if any). var bundlePath: AbsolutePath? { - guard !resources.isEmpty else { + guard !self.resources.isEmpty else { return .none } @@ -133,7 +133,7 @@ public final class ClangTargetBuildDescription { self.target = target self.toolsVersion = toolsVersion self.buildParameters = buildParameters - self.tempsPath = buildParameters.buildPath.appending(component: target.c99name + ".build") + self.tempsPath = target.tempsPath(buildParameters) self.derivedSources = Sources(paths: [], root: tempsPath.appending("DerivedSources")) // We did not use to apply package plugins to C-family targets in prior tools-versions, this preserves the behavior. @@ -225,7 +225,7 @@ public final class ClangTargetBuildDescription { if self.buildParameters.triple.isDarwin() { args += ["-fobjc-arc"] } - args += try buildParameters.targetTripleArgs(for: target) + args += try self.buildParameters.tripleArgs(for: target) args += optimizationArguments args += activeCompilationConditions diff --git a/Sources/Build/BuildDescription/ProductBuildDescription.swift b/Sources/Build/BuildDescription/ProductBuildDescription.swift index 3dda78588cf..8f7c33daa2e 100644 --- a/Sources/Build/BuildDescription/ProductBuildDescription.swift +++ b/Sources/Build/BuildDescription/ProductBuildDescription.swift @@ -322,7 +322,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription // setting is the package-level right now. We might need to figure out a better // answer for libraries if/when we support specifying deployment target at the // target-level. - args += try self.buildParameters.targetTripleArgs(for: self.product.targets[self.product.targets.startIndex]) + args += try self.buildParameters.tripleArgs(for: self.product.targets[self.product.targets.startIndex]) // Add arguments from declared build settings. args += self.buildSettingsFlags @@ -357,7 +357,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription // Library search path for the toolchain's copy of SwiftSyntax. #if BUILD_MACROS_AS_DYLIBS if product.type == .macro { - args += try ["-L", buildParameters.toolchain.hostLibDir.pathString] + args += try ["-L", defaultBuildParameters.toolchain.hostLibDir.pathString] } #endif diff --git a/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift b/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift new file mode 100644 index 00000000000..59e5e2abacd --- /dev/null +++ b/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2015-2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import struct Basics.AbsolutePath +import struct PackageGraph.ResolvedModule + +import SPMBuildCore + +extension ResolvedModule { + func tempsPath(_ buildParameters: BuildParameters) -> AbsolutePath { + let suffix = buildParameters.suffix(triple: self.buildTriple) + return buildParameters.buildPath.appending(component: "\(self.c99name)\(suffix).build") + } +} diff --git a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift index efb6a474906..11120f45c62 100644 --- a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift @@ -43,8 +43,11 @@ public final class SwiftTargetBuildDescription { /// a target is built. public let toolsVersion: ToolsVersion - /// The build parameters. - let buildParameters: BuildParameters + /// The build parameters for this target. + let defaultBuildParameters: BuildParameters + + /// The build parameters for build tools. + let toolsBuildParameters: BuildParameters /// Path to the temporary directory for this target. let tempsPath: AbsolutePath @@ -63,7 +66,7 @@ public final class SwiftTargetBuildDescription { /// Path to the bundle generated for this module (if any). var bundlePath: AbsolutePath? { if let bundleName = target.underlying.potentialBundleName, needsResourceBundle { - return self.buildParameters.bundlePath(named: bundleName) + return self.defaultBuildParameters.bundlePath(named: bundleName) } else { return .none } @@ -101,7 +104,7 @@ public final class SwiftTargetBuildDescription { let relativeSources = self.target.sources.relativePaths + self.derivedSources.relativePaths + self.pluginDerivedSources.relativePaths - let ltoEnabled = self.buildParameters.linkingParameters.linkTimeOptimizationMode != nil + let ltoEnabled = self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode != nil let objectFileExtension = ltoEnabled ? "bc" : "o" return try relativeSources.map { try AbsolutePath( @@ -112,16 +115,17 @@ public final class SwiftTargetBuildDescription { } var modulesPath: AbsolutePath { - return self.buildParameters.buildPath.appending(component: "Modules") + let suffix = self.defaultBuildParameters.suffix(triple: self.target.buildTriple) + return self.defaultBuildParameters.buildPath.appending(component: "Modules\(suffix)") } /// The path to the swiftmodule file after compilation. public var moduleOutputPath: AbsolutePath { // note: needs to be public because of sourcekit-lsp // If we're an executable and we're not allowing test targets to link against us, we hide the module. - let triple = buildParameters.triple + let triple = defaultBuildParameters.triple let allowLinkingAgainstExecutables = (triple.isDarwin() || triple.isLinux() || triple.isWindows()) && self.toolsVersion >= .v5_5 let dirPath = (target.type == .executable && !allowLinkingAgainstExecutables) ? self.tempsPath : self.modulesPath - return dirPath.appending(component: self.target.c99name + ".swiftmodule") + return dirPath.appending(component: "\(self.target.c99name).swiftmodule") } /// The path to the wrapped swift module which is created using the modulewrap tool. This is required @@ -131,7 +135,7 @@ public final class SwiftTargetBuildDescription { self.tempsPath.appending(component: self.target.c99name + ".swiftmodule.o") } - /// The path to the swifinterface file after compilation. + /// The path to the swiftinterface file after compilation. var parseableModuleInterfaceOutputPath: AbsolutePath { self.modulesPath.appending(component: self.target.c99name + ".swiftinterface") } @@ -242,7 +246,7 @@ public final class SwiftTargetBuildDescription { private let shouldGenerateTestObservation: Bool /// Whether to disable sandboxing (e.g. for macros). - private let disableSandbox: Bool + private let shouldDisableSandbox: Bool /// Create a new target description with target and build parameters. init( @@ -250,13 +254,14 @@ public final class SwiftTargetBuildDescription { target: ResolvedModule, toolsVersion: ToolsVersion, additionalFileRules: [FileRuleDescription] = [], - buildParameters: BuildParameters, + destinationBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters, buildToolPluginInvocationResults: [BuildToolPluginInvocationResult] = [], prebuildCommandResults: [PrebuildCommandResult] = [], requiredMacroProducts: [ResolvedProduct] = [], testTargetRole: TestTargetRole? = nil, shouldGenerateTestObservation: Bool = false, - disableSandbox: Bool, + shouldDisableSandbox: Bool, fileSystem: FileSystem, observabilityScope: ObservabilityScope ) throws { @@ -268,7 +273,9 @@ public final class SwiftTargetBuildDescription { self.package = package self.target = target self.toolsVersion = toolsVersion - self.buildParameters = buildParameters + self.defaultBuildParameters = destinationBuildParameters + self.toolsBuildParameters = toolsBuildParameters + // Unless mentioned explicitly, use the target type to determine if this is a test target. if let testTargetRole { self.testTargetRole = testTargetRole @@ -278,13 +285,13 @@ public final class SwiftTargetBuildDescription { self.testTargetRole = nil } - self.tempsPath = buildParameters.buildPath.appending(component: target.c99name + ".build") + self.tempsPath = target.tempsPath(destinationBuildParameters) self.derivedSources = Sources(paths: [], root: self.tempsPath.appending("DerivedSources")) self.buildToolPluginInvocationResults = buildToolPluginInvocationResults self.prebuildCommandResults = prebuildCommandResults self.requiredMacroProducts = requiredMacroProducts self.shouldGenerateTestObservation = shouldGenerateTestObservation - self.disableSandbox = disableSandbox + self.shouldDisableSandbox = shouldDisableSandbox self.fileSystem = fileSystem self.observabilityScope = observabilityScope @@ -292,7 +299,7 @@ public final class SwiftTargetBuildDescription { target: target, toolsVersion: toolsVersion, additionalFileRules: additionalFileRules, - buildParameters: buildParameters, + buildParameters: destinationBuildParameters, buildToolPluginInvocationResults: buildToolPluginInvocationResults, prebuildCommandResults: prebuildCommandResults, observabilityScope: observabilityScope @@ -332,11 +339,14 @@ public final class SwiftTargetBuildDescription { return } - guard self.buildParameters.triple.isDarwin(), self.buildParameters.testingParameters.experimentalTestOutput else { + guard + self.defaultBuildParameters.triple.isDarwin() && + self.defaultBuildParameters.testingParameters.experimentalTestOutput + else { return } - let content = generateTestObservationCode(buildParameters: self.buildParameters) + let content = generateTestObservationCode(buildParameters: self.defaultBuildParameters) // FIXME: We should generate this file during the actual build. self.derivedSources.relativePaths.append(subpath) @@ -355,7 +365,7 @@ public final class SwiftTargetBuildDescription { guard let bundlePath else { return } let mainPathSubstitution: String - if self.buildParameters.triple.isWASI() { + if self.defaultBuildParameters.triple.isWASI() { // We prefer compile-time evaluation of the bundle path here for WASI. There's no benefit in evaluating this // at runtime, especially as `Bundle` support in WASI Foundation is partial. We expect all resource paths to // evaluate to `/\(resourceBundleName)/\(resourcePath)`, which allows us to pass this path to JS APIs like @@ -412,12 +422,12 @@ public final class SwiftTargetBuildDescription { #if BUILD_MACROS_AS_DYLIBS self.requiredMacroProducts.forEach { macro in - args += ["-Xfrontend", "-load-plugin-library", "-Xfrontend", self.buildParameters.binaryPath(for: macro).pathString] + args += ["-Xfrontend", "-load-plugin-library", "-Xfrontend", self.toolsBuildParameters.binaryPath(for: macro).pathString] } #else try self.requiredMacroProducts.forEach { macro in if let macroTarget = macro.targets.first { - let executablePath = try self.buildParameters.binaryPath(for: macro).pathString + let executablePath = try self.toolsBuildParameters.binaryPath(for: macro).pathString args += ["-Xfrontend", "-load-plugin-executable", "-Xfrontend", "\(executablePath)#\(macroTarget.c99name)"] } else { throw InternalError("macro product \(macro.name) has no targets") // earlier validation should normally catch this @@ -425,8 +435,12 @@ public final class SwiftTargetBuildDescription { } #endif - if self.disableSandbox { - let toolchainSupportsDisablingSandbox = DriverSupport.checkSupportedFrontendFlags(flags: ["-disable-sandbox"], toolchain: self.buildParameters.toolchain, fileSystem: fileSystem) + if self.shouldDisableSandbox { + let toolchainSupportsDisablingSandbox = DriverSupport.checkSupportedFrontendFlags( + flags: ["-disable-sandbox"], + toolchain: self.defaultBuildParameters.toolchain, + fileSystem: fileSystem + ) if toolchainSupportsDisablingSandbox { args += ["-disable-sandbox"] } else { @@ -443,10 +457,10 @@ public final class SwiftTargetBuildDescription { /// The arguments needed to compile this target. public func compileArguments() throws -> [String] { var args = [String]() - args += try self.buildParameters.targetTripleArgs(for: self.target) + args += try self.defaultBuildParameters.tripleArgs(for: self.target) // pass `-v` during verbose builds. - if self.buildParameters.outputParameters.isVerbose { + if self.defaultBuildParameters.outputParameters.isVerbose { args += ["-v"] } @@ -454,22 +468,22 @@ public final class SwiftTargetBuildDescription { // // Technically, it should be enabled whenever WMO is off but we // don't currently make that distinction in SwiftPM - switch self.buildParameters.configuration { + switch self.defaultBuildParameters.configuration { case .debug: args += ["-enable-batch-mode"] case .release: break } - args += self.buildParameters.indexStoreArguments(for: self.target) + args += self.defaultBuildParameters.indexStoreArguments(for: self.target) args += self.optimizationArguments args += self.testingArguments - args += ["-j\(self.buildParameters.workers)"] + args += ["-j\(self.defaultBuildParameters.workers)"] args += self.activeCompilationConditions args += self.additionalFlags args += try self.moduleCacheArgs args += self.stdlibArguments - args += self.buildParameters.sanitizers.compileSwiftFlags() + args += self.defaultBuildParameters.sanitizers.compileSwiftFlags() args += ["-parseable-output"] // If we're compiling the main module of an executable other than the one that @@ -489,8 +503,8 @@ public final class SwiftTargetBuildDescription { // we can rename the symbol unconditionally. // No `-` for these flags because the set of Strings in driver.supportedFrontendFlags do // not have a leading `-` - if self.buildParameters.driverParameters.canRenameEntrypointFunctionName, - self.buildParameters.linkerFlagsForRenamingMainFunction(of: self.target) != nil + if self.defaultBuildParameters.driverParameters.canRenameEntrypointFunctionName, + self.defaultBuildParameters.linkerFlagsForRenamingMainFunction(of: self.target) != nil { args += ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "\(self.target.c99name)_main"] } @@ -503,7 +517,7 @@ public final class SwiftTargetBuildDescription { // Only add the build path to the framework search path if there are binary frameworks to link against. if !self.libraryBinaryPaths.isEmpty { - args += ["-F", self.buildParameters.buildPath.pathString] + args += ["-F", self.defaultBuildParameters.buildPath.pathString] } // Emit the ObjC compatibility header if enabled. @@ -512,12 +526,12 @@ public final class SwiftTargetBuildDescription { } // Add arguments needed for code coverage if it is enabled. - if self.buildParameters.testingParameters.enableCodeCoverage { + if self.defaultBuildParameters.testingParameters.enableCodeCoverage { args += ["-profile-coverage-mapping", "-profile-generate"] } // Add arguments to colorize output if stdout is tty - if self.buildParameters.outputParameters.isColorized { + if self.defaultBuildParameters.outputParameters.isColorized { args += ["-color-diagnostics"] } @@ -527,7 +541,7 @@ public final class SwiftTargetBuildDescription { switch testTargetRole { case .discovery, .entryPoint: for dependency in try self.target.recursiveTargetDependencies() { - let dependencyScope = self.buildParameters.createScope(for: dependency) + let dependencyScope = self.defaultBuildParameters.createScope(for: dependency) let dependencySwiftFlags = dependencyScope.evaluate(.OTHER_SWIFT_FLAGS) if let interopModeFlag = dependencySwiftFlags.first(where: { $0.hasPrefix("-cxx-interoperability-mode=") }) { args += [interopModeFlag] @@ -547,17 +561,17 @@ public final class SwiftTargetBuildDescription { // Add the output for the `.swiftinterface`, if requested or if library evolution has been enabled some other // way. - if self.buildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") { + if self.defaultBuildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") { args += ["-emit-module-interface-path", self.parseableModuleInterfaceOutputPath.pathString] } - args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags + args += self.defaultBuildParameters.toolchain.extraFlags.swiftCompilerFlags // User arguments (from -Xswiftc) should follow generated arguments to allow user overrides - args += self.buildParameters.flags.swiftCompilerFlags + args += self.defaultBuildParameters.flags.swiftCompilerFlags - args += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags() + args += self.defaultBuildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags() // User arguments (from -Xcc) should follow generated arguments to allow user overrides - args += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags() + args += self.defaultBuildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags() // TODO: Pass -Xcxx flags to swiftc (#6491) // Uncomment when downstream support arrives. @@ -566,7 +580,7 @@ public final class SwiftTargetBuildDescription { // args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags() // Enable the correct LTO mode if requested. - switch self.buildParameters.linkingParameters.linkTimeOptimizationMode { + switch self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode { case nil: break case .full: @@ -576,7 +590,7 @@ public final class SwiftTargetBuildDescription { } // Pass default include paths from the toolchain. - for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths { + for includeSearchPath in self.defaultBuildParameters.toolchain.includeSearchPaths { args += ["-I", includeSearchPath.pathString] } @@ -601,14 +615,14 @@ public final class SwiftTargetBuildDescription { args += self.package.packageNameArgument( target: self.target, - isPackageNameSupported: self.buildParameters.driverParameters.isPackageAccessModifierSupported + isPackageNameSupported: self.defaultBuildParameters.driverParameters.isPackageAccessModifierSupported ) args += try self.macroArguments() // rdar://117578677 // Pass -fno-omit-frame-pointer to support backtraces // this can be removed once the backtracer uses DWARF instead of frame pointers - if let omitFramePointers = self.buildParameters.debuggingParameters.omitFramePointers { + if let omitFramePointers = self.defaultBuildParameters.debuggingParameters.omitFramePointers { if omitFramePointers { args += ["-Xcc", "-fomit-frame-pointer"] } else { @@ -623,14 +637,14 @@ public final class SwiftTargetBuildDescription { /// such as emitting a module or supplementary outputs. public func emitCommandLine(scanInvocation: Bool = false) throws -> [String] { var result: [String] = [] - result.append(self.buildParameters.toolchain.swiftCompilerPath.pathString) + result.append(self.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) result.append("-module-name") result.append(self.target.c99name) result.append( contentsOf: self.package.packageNameArgument( target: self.target, - isPackageNameSupported: self.buildParameters.driverParameters.isPackageAccessModifierSupported + isPackageNameSupported: self.defaultBuildParameters.driverParameters.isPackageAccessModifierSupported ) ) if !scanInvocation { @@ -646,7 +660,7 @@ public final class SwiftTargetBuildDescription { result.append(try self.writeOutputFileMap().pathString) } - if self.buildParameters.useWholeModuleOptimization { + if self.defaultBuildParameters.useWholeModuleOptimization { result.append("-whole-module-optimization") result.append("-num-threads") result.append(String(ProcessInfo.processInfo.activeProcessorCount)) @@ -666,7 +680,7 @@ public final class SwiftTargetBuildDescription { /// Returns true if ObjC compatibility header should be emitted. private var shouldEmitObjCCompatibilityHeader: Bool { - self.buildParameters.triple.isDarwin() && self.target.type == .library + self.defaultBuildParameters.triple.isDarwin() && self.target.type == .library } func writeOutputFileMap() throws -> AbsolutePath { @@ -680,7 +694,7 @@ public final class SwiftTargetBuildDescription { """# - if self.buildParameters.useWholeModuleOptimization { + if self.defaultBuildParameters.useWholeModuleOptimization { let moduleName = self.target.c99name content += #""" @@ -711,7 +725,7 @@ public final class SwiftTargetBuildDescription { // Write out the entries for each source file. let sources = self.sources let objects = try self.objects - let ltoEnabled = self.buildParameters.linkingParameters.linkTimeOptimizationMode != nil + let ltoEnabled = self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode != nil let objectKey = ltoEnabled ? "llvm-bc" : "object" for idx in 0.. [String] { - let scope = self.buildParameters.createScope(for: self.target) + let scope = self.defaultBuildParameters.createScope(for: self.target) var flags: [String] = [] // A custom swift version. @@ -818,7 +832,7 @@ public final class SwiftTargetBuildDescription { // Include path for the toolchain's copy of SwiftSyntax. #if BUILD_MACROS_AS_DYLIBS if target.type == .macro { - flags += try ["-I", self.buildParameters.toolchain.hostLibDir.pathString] + flags += try ["-I", self.defaultBuildParameters.toolchain.hostLibDir.pathString] } #endif @@ -829,7 +843,7 @@ public final class SwiftTargetBuildDescription { private var activeCompilationConditions: [String] { var compilationConditions = ["-DSWIFT_PACKAGE"] - switch self.buildParameters.configuration { + switch self.defaultBuildParameters.configuration { case .debug: compilationConditions += ["-DDEBUG"] case .release: @@ -841,7 +855,7 @@ public final class SwiftTargetBuildDescription { /// Optimization arguments according to the build configuration. private var optimizationArguments: [String] { - switch self.buildParameters.configuration { + switch self.defaultBuildParameters.configuration { case .debug: return ["-Onone"] case .release: @@ -855,7 +869,7 @@ public final class SwiftTargetBuildDescription { // test targets must be built with -enable-testing // since its required for test discovery (the non objective-c reflection kind) return ["-enable-testing"] - } else if self.buildParameters.testingParameters.enableTestability { + } else if self.defaultBuildParameters.testingParameters.enableTestability { return ["-enable-testing"] } else { return [] @@ -865,20 +879,20 @@ public final class SwiftTargetBuildDescription { /// Module cache arguments. private var moduleCacheArgs: [String] { get throws { - ["-module-cache-path", try self.buildParameters.moduleCache.pathString] + ["-module-cache-path", try self.defaultBuildParameters.moduleCache.pathString] } } private var stdlibArguments: [String] { var arguments: [String] = [] - let isLinkingStaticStdlib = self.buildParameters.linkingParameters.shouldLinkStaticSwiftStdlib - && self.buildParameters.triple.isSupportingStaticStdlib + let isLinkingStaticStdlib = self.defaultBuildParameters.linkingParameters.shouldLinkStaticSwiftStdlib + && self.defaultBuildParameters.triple.isSupportingStaticStdlib if isLinkingStaticStdlib { arguments += ["-static-stdlib"] } - if let resourcesPath = self.buildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) { + if let resourcesPath = self.defaultBuildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) { arguments += ["-resource-dir", "\(resourcesPath)"] } diff --git a/Sources/Build/BuildDescription/TargetBuildDescription.swift b/Sources/Build/BuildDescription/TargetBuildDescription.swift index 4ddda8dec70..3c6ace54221 100644 --- a/Sources/Build/BuildDescription/TargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/TargetBuildDescription.swift @@ -101,7 +101,7 @@ public enum TargetBuildDescription { var buildParameters: BuildParameters { switch self { case .swift(let swiftTargetBuildDescription): - return swiftTargetBuildDescription.buildParameters + return swiftTargetBuildDescription.defaultBuildParameters case .clang(let clangTargetBuildDescription): return clangTargetBuildDescription.buildParameters } diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift index 70ae4ee508a..e6ddfc1a4fb 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift @@ -93,7 +93,7 @@ extension LLBuildManifestBuilder { let additionalInputs = try addBuildToolPlugins(.clang(target)) // Create a phony node to represent the entire target. - let targetName = target.target.getLLBuildTargetName(config: target.buildParameters.buildConfig) + let targetName = target.target.getLLBuildTargetName(buildParameters: target.buildParameters) let output: Node = .virtual(targetName) self.manifest.addNode(output, toTarget: targetName) diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift index 3061b25ee7b..cf8a797ed9c 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift @@ -15,7 +15,7 @@ import struct LLBuildManifest.Node extension LLBuildManifestBuilder { func createProductCommand(_ buildProduct: ProductBuildDescription) throws { - let cmdName = try buildProduct.product.getCommandName(config: buildProduct.buildParameters.buildConfig) + let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters) // Add dependency on Info.plist generation on Darwin platforms. let testInputs: [AbsolutePath] @@ -34,7 +34,7 @@ extension LLBuildManifestBuilder { } // Create a phony node to represent the entire target. - let targetName = try buildProduct.product.getLLBuildTargetName(config: buildProduct.buildParameters.buildConfig) + let targetName = try buildProduct.product.getLLBuildTargetName(buildParameters: buildProduct.buildParameters) let output: Node = .virtual(targetName) let finalProductNode: Node @@ -85,7 +85,7 @@ extension LLBuildManifestBuilder { outputPath: plistPath ) - let cmdName = try buildProduct.product.getCommandName(config: buildProduct.buildParameters.buildConfig) + let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters) let codeSigningOutput = Node.virtual(targetName + "-CodeSigning") try self.manifest.addShellCmd( name: "\(cmdName)-entitlements", diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift index a82da020b8c..a2cf42bf2fb 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift @@ -45,7 +45,7 @@ extension LLBuildManifestBuilder { let moduleNode = Node.file(target.moduleOutputPath) let cmdOutputs = objectNodes + [moduleNode] - if target.buildParameters.driverParameters.useIntegratedSwiftDriver { + if target.defaultBuildParameters.driverParameters.useIntegratedSwiftDriver { try self.addSwiftCmdsViaIntegratedDriver( target, inputs: inputs, @@ -68,7 +68,7 @@ extension LLBuildManifestBuilder { // jobs needed to build this Swift target. var commandLine = try target.emitCommandLine() commandLine.append("-driver-use-frontend-path") - commandLine.append(target.buildParameters.toolchain.swiftCompilerPath.pathString) + commandLine.append(target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) // FIXME: At some point SwiftPM should provide its own executor for // running jobs/launching processes during planning let resolver = try ArgsResolver(fileSystem: target.fileSystem) @@ -132,7 +132,7 @@ extension LLBuildManifestBuilder { // common intermediate dependency modules, such dependencies can lead // to cycles in the resulting manifest. var manifestNodeInputs: [Node] = [] - if targetDescription.buildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) { + if targetDescription.defaultBuildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) { manifestNodeInputs = jobInputs } else { manifestNodeInputs = (inputs + jobInputs).uniqued() @@ -192,7 +192,9 @@ extension LLBuildManifestBuilder { // Sort the product targets in topological order in order to collect and "bubble up" // their respective dependency graphs to the depending targets. let nodes: [ResolvedModule.Dependency] = try self.plan.targetMap.keys.compactMap { - guard let target = self.plan.graph.allTargets[$0] else { throw InternalError("unknown target \($0)") } + guard let target = self.plan.graph.allTargets[$0] else { + throw InternalError("unknown target \($0)") + } return ResolvedModule.Dependency.target(target, conditions: []) } let allPackageDependencies = try topologicalSort(nodes, successors: { $0.dependencies }) @@ -285,7 +287,7 @@ extension LLBuildManifestBuilder { // jobs needed to build this Swift target. var commandLine = try targetDescription.emitCommandLine() commandLine.append("-driver-use-frontend-path") - commandLine.append(targetDescription.buildParameters.toolchain.swiftCompilerPath.pathString) + commandLine.append(targetDescription.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) commandLine.append("-experimental-explicit-module-build") let resolver = try ArgsResolver(fileSystem: self.fileSystem) let executor = SPMSwiftDriverExecutor( @@ -376,14 +378,14 @@ extension LLBuildManifestBuilder { cmdOutputs: [Node] ) throws { let isLibrary = target.target.type == .library || target.target.type == .test - let cmdName = target.target.getCommandName(config: target.buildParameters.buildConfig) + let cmdName = target.target.getCommandName(buildParameters: target.defaultBuildParameters) self.manifest.addWriteSourcesFileListCommand(sources: target.sources, sourcesFileListPath: target.sourcesFileListPath) self.manifest.addSwiftCmd( name: cmdName, inputs: inputs + [Node.file(target.sourcesFileListPath)], outputs: cmdOutputs, - executable: target.buildParameters.toolchain.swiftCompilerPath, + executable: target.defaultBuildParameters.toolchain.swiftCompilerPath, moduleName: target.target.c99name, moduleAliases: target.target.moduleAliases, moduleOutputPath: target.moduleOutputPath, @@ -394,7 +396,7 @@ extension LLBuildManifestBuilder { sources: target.sources, fileList: target.sourcesFileListPath, isLibrary: isLibrary, - wholeModuleOptimization: target.buildParameters.configuration == .release, + wholeModuleOptimization: target.defaultBuildParameters.configuration == .release, outputFileMapPath: try target.writeOutputFileMap() // FIXME: Eliminate side effect. ) } @@ -404,7 +406,7 @@ extension LLBuildManifestBuilder { ) throws -> [Node] { var inputs = target.sources.map(Node.file) - let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.buildParameters) + let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.defaultBuildParameters) inputs.append(.file(swiftVersionFilePath)) // Add resources node as the input to the target. This isn't great because we @@ -455,7 +457,7 @@ extension LLBuildManifestBuilder { } } - for dependency in target.target.dependencies(satisfying: target.buildParameters.buildEnvironment) { + for dependency in target.target.dependencies(satisfying: target.defaultBuildParameters.buildEnvironment) { switch dependency { case .target(let target, _): try addStaticTargetInputs(target) @@ -482,7 +484,7 @@ extension LLBuildManifestBuilder { } for binaryPath in target.libraryBinaryPaths { - let path = target.buildParameters.destinationPath(forBinaryAt: binaryPath) + let path = target.defaultBuildParameters.destinationPath(forBinaryAt: binaryPath) if self.fileSystem.isDirectory(binaryPath) { inputs.append(directory: path) } else { @@ -494,7 +496,7 @@ extension LLBuildManifestBuilder { // Depend on any required macro product's output. try target.requiredMacroProducts.forEach { macro in - try inputs.append(.virtual(macro.getLLBuildTargetName(config: target.buildParameters.buildConfig))) + try inputs.append(.virtual(macro.getLLBuildTargetName(buildParameters: target.defaultBuildParameters))) } return inputs + additionalInputs @@ -503,7 +505,7 @@ extension LLBuildManifestBuilder { /// 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: target.buildParameters.buildConfig) + let targetName = target.target.getLLBuildTargetName(buildParameters: target.defaultBuildParameters) let targetOutput: Node = .virtual(targetName) self.manifest.addNode(targetOutput, toTarget: targetName) @@ -512,7 +514,7 @@ extension LLBuildManifestBuilder { inputs: cmdOutputs, outputs: [targetOutput] ) - if self.plan.graph.isInRootPackages(target.target, satisfying: target.buildParameters.buildEnvironment) { + if self.plan.graph.isInRootPackages(target.target, satisfying: target.defaultBuildParameters.buildEnvironment) { if !target.isTestTarget { self.addNode(targetOutput, toTarget: .main) } @@ -522,13 +524,13 @@ extension LLBuildManifestBuilder { private func addModuleWrapCmd(_ target: SwiftTargetBuildDescription) throws { // Add commands to perform the module wrapping Swift modules when debugging strategy is `modulewrap`. - guard target.buildParameters.debuggingStrategy == .modulewrap else { return } + guard target.defaultBuildParameters.debuggingStrategy == .modulewrap else { return } var moduleWrapArgs = [ - target.buildParameters.toolchain.swiftCompilerPath.pathString, + target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString, "-modulewrap", target.moduleOutputPath.pathString, "-o", target.wrappedModuleOutputPath.pathString, ] - moduleWrapArgs += try target.buildParameters.targetTripleArgs(for: target.target) + moduleWrapArgs += try target.defaultBuildParameters.tripleArgs(for: target.target) self.manifest.addShellCmd( name: target.wrappedModuleOutputPath.pathString, description: "Wrapping AST for \(target.target.name) for debugging", diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift index 77c79da1915..f4439ec7af9 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -317,31 +317,33 @@ extension TargetBuildDescription { } extension ResolvedModule { - public func getCommandName(config: String) -> String { - "C." + self.getLLBuildTargetName(config: config) + package func getCommandName(buildParameters: BuildParameters) -> String { + "C." + self.getLLBuildTargetName(buildParameters: buildParameters) } - public func getLLBuildTargetName(config: String) -> String { - "\(name)-\(config).module" + package func getLLBuildTargetName(buildParameters: BuildParameters) -> String { + "\(self.name)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module" } - public func getLLBuildResourcesCmdName(config: String) -> String { - "\(name)-\(config).module-resources" + package func getLLBuildResourcesCmdName(config: String) -> String { + "\(self.name)-\(config).module-resources" } } extension ResolvedProduct { - public func getLLBuildTargetName(config: String) throws -> String { - let potentialExecutableTargetName = "\(name)-\(config).exe" - let potentialLibraryTargetName = "\(name)-\(config).dylib" + package func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String { + let config = buildParameters.buildConfig + let suffix = buildParameters.suffix(triple: self.buildTriple) + let potentialExecutableTargetName = "\(name)-\(config)\(suffix).exe" + let potentialLibraryTargetName = "\(name)-\(config)\(suffix).dylib" switch type { case .library(.dynamic): return potentialLibraryTargetName case .test: - return "\(name)-\(config).test" + return "\(name)-\(config)\(suffix).test" case .library(.static): - return "\(name)-\(config).a" + return "\(name)-\(config)\(suffix).a" case .library(.automatic): throw InternalError("automatic library not supported") case .executable, .snippet: @@ -357,8 +359,8 @@ extension ResolvedProduct { } } - public func getCommandName(config: String) throws -> String { - try "C." + self.getLLBuildTargetName(config: config) + public func getCommandName(buildParameters: BuildParameters) throws -> String { + try "C.\(self.getLLBuildTargetName(buildParameters: buildParameters))\(buildParameters.suffix(triple: self.buildTriple))" } } diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index b478e20567d..0882286eaf7 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -269,7 +269,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } // TODO: Currently this function will only match frameworks. - internal func detectUnexpressedDependencies( + func detectUnexpressedDependencies( availableLibraries: [LibraryMetadata], targetDependencyMap: [String: [String]]? ) { @@ -295,7 +295,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } let usedSDKDependencies: [String] = Set(possibleTempsPaths).flatMap { possibleTempsPath in - guard let contents = try? self.fileSystem.readFileContents(possibleTempsPath.appending(component: "\(c99name).d")) else { + guard let contents = try? self.fileSystem.readFileContents( + possibleTempsPath.appending(component: "\(c99name).d") + ) else { return [String]() } @@ -520,7 +522,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS let graph = try getPackageGraph() if let result = subset.llbuildTargetName( for: graph, - config: self.productsBuildParameters.configuration.dirname, + buildParameters: self.productsBuildParameters, observabilityScope: self.observabilityScope ) { return result @@ -538,17 +540,20 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // Invoke any build tool plugins in the graph to generate prebuild commands and build commands. if let pluginConfiguration, !self.productsBuildParameters.shouldSkipBuilding { // Hacky workaround for rdar://120560817, but it replicates precisely enough the original behavior before - // products/tools build parameters were split. Ideally we want to have specify the correct path at the time + // products/tools build parameters were split. Ideally we want to specify the correct path at the time // when `toolsBuildParameters` is initialized, but we have too many places in the codebase where that's // done, which makes it hard to realign them all at once. var pluginsBuildParameters = self.toolsBuildParameters pluginsBuildParameters.dataPath = pluginsBuildParameters.dataPath.parentDirectory.appending(components: ["plugins", "tools"]) + var buildToolsGraph = graph + try buildToolsGraph.updateBuildTripleRecursively(.tools) + let buildOperationForPluginDependencies = BuildOperation( // FIXME: this doesn't maintain the products/tools split cleanly productsBuildParameters: pluginsBuildParameters, toolsBuildParameters: pluginsBuildParameters, cacheBuildManifest: false, - packageGraphLoader: { return graph }, + packageGraphLoader: { buildToolsGraph }, additionalFileRules: self.additionalFileRules, pkgConfigDirectories: self.pkgConfigDirectories, dependenciesByRootPackageIdentity: [:], @@ -558,7 +563,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS fileSystem: self.fileSystem, observabilityScope: self.observabilityScope ) - buildToolPluginInvocationResults = try graph.invokeBuildToolPlugins( + buildToolPluginInvocationResults = try buildToolsGraph.invokeBuildToolPlugins( outputDir: pluginConfiguration.workDirectory.appending("outputs"), buildParameters: pluginsBuildParameters, additionalFileRules: self.additionalFileRules, @@ -576,7 +581,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } } - // Surface any diagnostics from build tool plugins. var succeeded = true for (_, (target, results)) in buildToolPluginInvocationResults { @@ -615,7 +619,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // Emit warnings about any unhandled files in authored packages. We do this after applying build tool plugins, once we know what files they handled. // rdar://113256834 This fix works for the plugins that do not have PreBuildCommands. - let targetsToConsider: [ResolvedTarget] + let targetsToConsider: [ResolvedModule] if let subset = subset, let recursiveDependencies = try subset.recursiveDependencies(for: graph, observabilityScope: observabilityScope) { targetsToConsider = recursiveDependencies @@ -656,7 +660,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // Create the build plan based, on the graph and any information from plugins. let plan = try BuildPlan( - productsBuildParameters: self.productsBuildParameters, + destinationBuildParameters: self.productsBuildParameters, toolsBuildParameters: self.toolsBuildParameters, graph: graph, additionalFileRules: additionalFileRules, @@ -899,9 +903,11 @@ extension BuildSubset { } /// Returns the name of the llbuild target that corresponds to the build subset. - func llbuildTargetName(for graph: ModulesGraph, config: String, observabilityScope: ObservabilityScope) - -> String? - { + func llbuildTargetName( + for graph: ModulesGraph, + buildParameters: BuildParameters, + observabilityScope: ObservabilityScope + ) -> String? { switch self { case .allExcludingTests: return LLBuildManifestBuilder.TargetKind.main.targetName @@ -922,14 +928,14 @@ extension BuildSubset { return LLBuildManifestBuilder.TargetKind.main.targetName } return observabilityScope.trap { - try product.getLLBuildTargetName(config: config) + try product.getLLBuildTargetName(buildParameters: buildParameters) } case .target(let targetName): guard let target = graph.allTargets.first(where: { $0.name == targetName }) else { observabilityScope.emit(error: "no target named '\(targetName)'") return nil } - return target.getLLBuildTargetName(config: config) + return target.getLLBuildTargetName(buildParameters: buildParameters) } } } diff --git a/Sources/Build/BuildPlan/BuildPlan+Product.swift b/Sources/Build/BuildPlan/BuildPlan+Product.swift index 5ba6f56dceb..a0cb3600bb9 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Product.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Product.swift @@ -81,7 +81,7 @@ extension BuildPlan { switch target.underlying { case is SwiftTarget: // Swift targets are guaranteed to have a corresponding Swift description. - guard case .swift(let description) = targetMap[target.id] else { + guard case .swift(let description) = self.targetMap[target.id] else { throw InternalError("unknown target \(target)") } @@ -103,13 +103,13 @@ extension BuildPlan { buildProduct.staticTargets = dependencies.staticTargets buildProduct.dylibs = try dependencies.dylibs.map { - guard let product = productMap[$0.id] else { + guard let product = self.productMap[$0.id] else { throw InternalError("unknown product \($0)") } return product } buildProduct.objects += try dependencies.staticTargets.flatMap { targetName -> [AbsolutePath] in - guard let target = targetMap[targetName.id] else { + guard let target = self.targetMap[targetName.id] else { throw InternalError("unknown target \(targetName)") } return try target.objects @@ -231,9 +231,11 @@ extension BuildPlan { if product.targets.contains(id: target.id) { staticTargets.append(target) } - // Library targets should always be included. + // Library targets should always be included for the same build triple. case .library: - staticTargets.append(target) + if target.buildTriple == product.buildTriple { + staticTargets.append(target) + } // Add system target to system targets array. case .systemModule: systemModules.append(target) diff --git a/Sources/Build/BuildPlan/BuildPlan+Swift.swift b/Sources/Build/BuildPlan/BuildPlan+Swift.swift index 36b1cacde0c..058631598f2 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Swift.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Swift.swift @@ -19,7 +19,7 @@ extension BuildPlan { func plan(swiftTarget: SwiftTargetBuildDescription) throws { // We need to iterate recursive dependencies because Swift compiler needs to see all the targets a target // depends on. - let environment = swiftTarget.buildParameters.buildEnvironment + let environment = swiftTarget.defaultBuildParameters.buildEnvironment for case .target(let dependency, _) in try swiftTarget.target.recursiveDependencies(satisfying: environment) { switch dependency.underlying { case let underlyingTarget as ClangTarget where underlyingTarget.type == .library: @@ -40,7 +40,7 @@ extension BuildPlan { swiftTarget.additionalFlags += try pkgConfig(for: target).cFlags case let target as BinaryTarget: if case .xcframework = target.kind { - let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.buildParameters.triple) + let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.defaultBuildParameters.triple) for library in libraries { library.headersPaths.forEach { swiftTarget.additionalFlags += ["-I", $0.pathString, "-Xcc", "-I", "-Xcc", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan+Test.swift b/Sources/Build/BuildPlan/BuildPlan+Test.swift index 0d3263f0f01..b82828608f1 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Test.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Test.swift @@ -26,15 +26,16 @@ import protocol TSCBasic.FileSystem extension BuildPlan { static func makeDerivedTestTargets( - _ buildParameters: BuildParameters, + destinationBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters, _ graph: ModulesGraph, - _ disableSandbox: Bool, + shouldDisableSandbox: Bool, _ fileSystem: FileSystem, _ observabilityScope: ObservabilityScope ) throws -> [(product: ResolvedProduct, discoveryTargetBuildDescription: SwiftTargetBuildDescription?, entryPointTargetBuildDescription: SwiftTargetBuildDescription)] { - guard buildParameters.testingParameters.testProductStyle.requiresAdditionalDerivedTestTargets, - case .entryPointExecutable(let explicitlyEnabledDiscovery, let explicitlySpecifiedPath) = - buildParameters.testingParameters.testProductStyle + guard destinationBuildParameters.testingParameters.testProductStyle.requiresAdditionalDerivedTestTargets, + case .entryPointExecutable(let explicitlyEnabledDiscovery, let explicitlySpecifiedPath) = + destinationBuildParameters.testingParameters.testProductStyle else { throw InternalError("makeTestManifestTargets should not be used for build plan which does not require additional derived test targets") } @@ -68,7 +69,7 @@ extension BuildPlan { /// Generates test discovery targets, which contain derived sources listing the discovered tests. func generateDiscoveryTargets() throws -> (target: SwiftTarget, resolved: ResolvedModule, buildDescription: SwiftTargetBuildDescription) { let discoveryTargetName = "\(package.manifest.displayName)PackageDiscoveredTests" - let discoveryDerivedDir = buildParameters.buildPath.appending(components: "\(discoveryTargetName).derived") + let discoveryDerivedDir = destinationBuildParameters.buildPath.appending(components: "\(discoveryTargetName).derived") let discoveryMainFile = discoveryDerivedDir.appending(component: TestDiscoveryTool.mainFileName) var discoveryPaths: [AbsolutePath] = [] @@ -84,7 +85,7 @@ extension BuildPlan { packageAccess: true, // test target is allowed access to package decls by default testDiscoverySrc: Sources(paths: discoveryPaths, root: discoveryDerivedDir) ) - let discoveryResolvedTarget = ResolvedModule( + var discoveryResolvedTarget = ResolvedModule( packageIdentity: testProduct.packageIdentity, underlying: discoveryTarget, dependencies: testProduct.targets.map { .target($0, conditions: []) }, @@ -92,13 +93,23 @@ extension BuildPlan { supportedPlatforms: testProduct.supportedPlatforms, platformVersionProvider: testProduct.platformVersionProvider ) + + discoveryResolvedTarget.buildTriple = testProduct.buildTriple + let discoveryTargetBuildParameters: BuildParameters + switch discoveryResolvedTarget.buildTriple { + case .tools: + discoveryTargetBuildParameters = toolsBuildParameters + case .destination: + discoveryTargetBuildParameters = destinationBuildParameters + } let discoveryTargetBuildDescription = try SwiftTargetBuildDescription( package: package, target: discoveryResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: discoveryTargetBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .discovery, - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -112,8 +123,8 @@ extension BuildPlan { swiftTargetDependencies: [Target.Dependency], resolvedTargetDependencies: [ResolvedModule.Dependency] ) throws -> SwiftTargetBuildDescription { - let entryPointDerivedDir = buildParameters.buildPath.appending(components: "\(testProduct.name).derived") - let entryPointMainFileName = TestEntryPointTool.mainFileName(for: buildParameters.testingParameters.library) + let entryPointDerivedDir = destinationBuildParameters.buildPath.appending(components: "\(testProduct.name).derived") + let entryPointMainFileName = TestEntryPointTool.mainFileName(for: destinationBuildParameters.testingParameters.library) let entryPointMainFile = entryPointDerivedDir.appending(component: entryPointMainFileName) let entryPointSources = Sources(paths: [entryPointMainFile], root: entryPointDerivedDir) @@ -124,7 +135,7 @@ extension BuildPlan { packageAccess: true, // test target is allowed access to package decls testEntryPointSources: entryPointSources ) - let entryPointResolvedTarget = ResolvedModule( + var entryPointResolvedTarget = ResolvedModule( packageIdentity: testProduct.packageIdentity, underlying: entryPointTarget, dependencies: testProduct.targets.map { .target($0, conditions: []) } + resolvedTargetDependencies, @@ -132,13 +143,23 @@ extension BuildPlan { supportedPlatforms: testProduct.supportedPlatforms, platformVersionProvider: testProduct.platformVersionProvider ) + entryPointResolvedTarget.buildTriple = testProduct.buildTriple + let entryPointBuildParameters: BuildParameters + switch entryPointResolvedTarget.buildTriple { + case .tools: + entryPointBuildParameters = toolsBuildParameters + case .destination: + entryPointBuildParameters = destinationBuildParameters + } + return try SwiftTargetBuildDescription( package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: entryPointBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .entryPoint(isSynthesized: true), - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -148,7 +169,7 @@ extension BuildPlan { let swiftTargetDependencies: [Target.Dependency] let resolvedTargetDependencies: [ResolvedModule.Dependency] - switch buildParameters.testingParameters.library { + switch destinationBuildParameters.testingParameters.library { case .xctest: discoveryTargets = try generateDiscoveryTargets() swiftTargetDependencies = [.target(discoveryTargets!.target, conditions: [])] @@ -181,9 +202,10 @@ extension BuildPlan { package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: destinationBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .entryPoint(isSynthesized: false), - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -203,9 +225,10 @@ extension BuildPlan { package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: destinationBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .entryPoint(isSynthesized: false), - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index 8ff9dd79baa..f24d123e918 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -128,12 +128,13 @@ extension BuildParameters { } /// Computes the target triple arguments for a given resolved target. - public func targetTripleArgs(for target: ResolvedModule) throws -> [String] { + public func tripleArgs(for target: ResolvedModule) throws -> [String] { + // confusingly enough this is the triple argument, not the target argument var args = ["-target"] // Compute the triple string for Darwin platform using the platform version. if self.triple.isDarwin() { - let platform = buildEnvironment.platform + let platform = self.buildEnvironment.platform let supportedPlatform = target.getSupportedPlatform(for: platform, usingXCTest: target.type == .test) args += [self.triple.tripleString(forPlatformVersion: supportedPlatform.version.versionString)] } else { @@ -185,16 +186,6 @@ public class BuildPlan: SPMBuildCore.BuildPlan { /// Build parameters used for tools. public let toolsBuildParameters: BuildParameters - /// Triple for which this target is compiled. - private func buildTriple(for target: ResolvedModule) -> Basics.Triple { - self.buildParameters(for: target).triple - } - - /// Triple for which this product is compiled. - private func buildTriple(for product: ResolvedProduct) -> Basics.Triple { - self.buildParameters(for: product).triple - } - /// The package graph. public let graph: ModulesGraph @@ -231,14 +222,14 @@ public class BuildPlan: SPMBuildCore.BuildPlan { /// Cache for pkgConfig flags. private var pkgConfigCache = [SystemLibraryTarget: (cFlags: [String], libs: [String])]() - /// Cache for library information. + /// Cache for library information. private var externalLibrariesCache = [BinaryTarget: [LibraryInfo]]() - /// Cache for tools information. + /// Cache for tools information. var externalExecutablesCache = [BinaryTarget: [ExecutableInfo]]() /// Whether to disable sandboxing (e.g. for macros). - private let disableSandbox: Bool + private let shouldDisableSandbox: Bool /// The filesystem to operate on. let fileSystem: any FileSystem @@ -246,18 +237,18 @@ public class BuildPlan: SPMBuildCore.BuildPlan { /// ObservabilityScope with which to emit diagnostics let observabilityScope: ObservabilityScope - @available(*, deprecated, renamed: "init(productsBuildParameters:toolsBuildParameters:graph:)") + @available(*, deprecated, renamed: "init(destinationBuildParameters:toolsBuildParameters:graph:)") public convenience init( buildParameters: BuildParameters, graph: ModulesGraph, additionalFileRules: [FileRuleDescription] = [], - buildToolPluginInvocationResults: [ResolvedTarget.ID: [BuildToolPluginInvocationResult]] = [:], - prebuildCommandResults: [ResolvedTarget.ID: [PrebuildCommandResult]] = [:], + buildToolPluginInvocationResults: [ResolvedModule.ID: [BuildToolPluginInvocationResult]] = [:], + prebuildCommandResults: [ResolvedModule.ID: [PrebuildCommandResult]] = [:], fileSystem: any FileSystem, observabilityScope: ObservabilityScope ) throws { try self.init( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, additionalFileRules: additionalFileRules, @@ -268,11 +259,29 @@ public class BuildPlan: SPMBuildCore.BuildPlan { ) } - /// Create a build plan with a package graph and explicitly distinct build parameters for products and tools. - public init( + @available(*, deprecated, renamed: "init(destinationBuildParameters:toolsBuildParameters:graph:fileSystem:observabilityScope:)") + public convenience init( productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters, graph: ModulesGraph, + fileSystem: any FileSystem, + observabilityScope: ObservabilityScope + ) throws { + try self.init( + destinationBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters, + graph: graph, + fileSystem: fileSystem, + observabilityScope: observabilityScope + ) + } + + /// Create a build plan with a package graph and explicitly distinct build parameters for destination platform and + /// tools platform. + public init( + destinationBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters, + graph: ModulesGraph, additionalFileRules: [FileRuleDescription] = [], buildToolPluginInvocationResults: [ResolvedModule.ID: [BuildToolPluginInvocationResult]] = [:], prebuildCommandResults: [ResolvedModule.ID: [PrebuildCommandResult]] = [:], @@ -280,16 +289,17 @@ public class BuildPlan: SPMBuildCore.BuildPlan { fileSystem: any FileSystem, observabilityScope: ObservabilityScope ) throws { - self.destinationBuildParameters = productsBuildParameters + self.destinationBuildParameters = destinationBuildParameters self.toolsBuildParameters = toolsBuildParameters self.graph = graph self.buildToolPluginInvocationResults = buildToolPluginInvocationResults self.prebuildCommandResults = prebuildCommandResults - self.disableSandbox = disableSandbox + self.shouldDisableSandbox = disableSandbox self.fileSystem = fileSystem self.observabilityScope = observabilityScope.makeChildScope(description: "Build Plan") - var productMap: [ResolvedProduct.ID: (product: ResolvedProduct, buildDescription: ProductBuildDescription)] = [:] + var productMap: [ResolvedProduct.ID: (product: ResolvedProduct, buildDescription: ProductBuildDescription)] = + [:] // Create product description for each product we have in the package graph that is eligible. for product in graph.allProducts where product.shouldCreateProductDescription { let buildParameters: BuildParameters @@ -297,7 +307,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { case .tools: buildParameters = toolsBuildParameters case .destination: - buildParameters = productsBuildParameters + buildParameters = destinationBuildParameters } guard let package = graph.package(for: product) else { @@ -335,7 +345,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { case .tools: buildParameters = toolsBuildParameters case .destination: - buildParameters = productsBuildParameters + buildParameters = destinationBuildParameters } // Validate the product dependencies of this target. @@ -384,12 +394,13 @@ public class BuildPlan: SPMBuildCore.BuildPlan { target: target, toolsVersion: toolsVersion, additionalFileRules: additionalFileRules, - buildParameters: buildParameters, + destinationBuildParameters: buildParameters, + toolsBuildParameters: toolsBuildParameters, buildToolPluginInvocationResults: buildToolPluginInvocationResults[target.id] ?? [], prebuildCommandResults: prebuildCommandResults[target.id] ?? [], requiredMacroProducts: requiredMacroProducts, shouldGenerateTestObservation: generateTestObservation, - disableSandbox: self.disableSandbox, + shouldDisableSandbox: self.shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -441,19 +452,21 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } // Plan the derived test targets, if necessary. - if productsBuildParameters.testingParameters.testProductStyle.requiresAdditionalDerivedTestTargets { + if destinationBuildParameters.testingParameters.testProductStyle.requiresAdditionalDerivedTestTargets { let derivedTestTargets = try Self.makeDerivedTestTargets( - productsBuildParameters, + destinationBuildParameters: destinationBuildParameters, + toolsBuildParameters: toolsBuildParameters, graph, - self.disableSandbox, + shouldDisableSandbox: self.shouldDisableSandbox, self.fileSystem, self.observabilityScope ) for item in derivedTestTargets { var derivedTestTargets = [item.entryPointTargetBuildDescription.target] - targetMap[item.entryPointTargetBuildDescription.target.id] = - .swift(item.entryPointTargetBuildDescription) + targetMap[item.entryPointTargetBuildDescription.target.id] = .swift( + item.entryPointTargetBuildDescription + ) if let discoveryTargetBuildDescription = item.discoveryTargetBuildDescription { targetMap[discoveryTargetBuildDescription.target.id] = .swift(discoveryTargetBuildDescription) diff --git a/Sources/Build/CMakeLists.txt b/Sources/Build/CMakeLists.txt index fcc51aed76d..9412aa38590 100644 --- a/Sources/Build/CMakeLists.txt +++ b/Sources/Build/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(Build BuildDescription/ClangTargetBuildDescription.swift BuildDescription/PluginDescription.swift BuildDescription/ProductBuildDescription.swift + BuildDescription/ResolvedModule+BuildDescription.swift BuildDescription/SwiftTargetBuildDescription.swift BuildDescription/TargetBuildDescription.swift BuildManifest/LLBuildManifestBuilder.swift diff --git a/Sources/Commands/PackageCommands/PluginCommand.swift b/Sources/Commands/PackageCommands/PluginCommand.swift index 6f7c95bce4c..02d935e0ee1 100644 --- a/Sources/Commands/PackageCommands/PluginCommand.swift +++ b/Sources/Commands/PackageCommands/PluginCommand.swift @@ -14,7 +14,9 @@ import ArgumentParser import Basics import CoreCommands import Dispatch + import PackageGraph + import PackageModel import enum TSCBasic.ProcessEnv @@ -315,6 +317,9 @@ struct PluginCommand: SwiftCommand { let toolSearchDirs = [try swiftCommandState.getTargetToolchain().swiftCompilerPath.parentDirectory] + getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: .none) + var buildToolsGraph = packageGraph + try buildToolsGraph.updateBuildTripleRecursively(.tools) + let buildParameters = try swiftCommandState.toolsBuildParameters // Build or bring up-to-date any executable host-side tools on which this plugin depends. Add them and any binary dependencies to the tool-names-to-path map. let buildSystem = try swiftCommandState.createBuildSystem( @@ -323,10 +328,12 @@ struct PluginCommand: SwiftCommand { // Force all dependencies to be built for the host, to work around the fact that BuildOperation.plan // knows to compile build tool plugin dependencies for the host but does not do the same for command // plugins. - productsBuildParameters: buildParameters + productsBuildParameters: buildParameters, + packageGraphLoader: { buildToolsGraph } ) + let accessibleTools = try plugin.processAccessibleTools( - packageGraph: packageGraph, + packageGraph: buildToolsGraph, fileSystem: swiftCommandState.fileSystem, environment: buildParameters.buildEnvironment, for: try pluginScriptRunner.hostTriple diff --git a/Sources/Commands/Utilities/SymbolGraphExtract.swift b/Sources/Commands/Utilities/SymbolGraphExtract.swift index 20f85ef6c16..aa968653269 100644 --- a/Sources/Commands/Utilities/SymbolGraphExtract.swift +++ b/Sources/Commands/Utilities/SymbolGraphExtract.swift @@ -66,7 +66,7 @@ public struct SymbolGraphExtract { // Construct arguments for extracting symbols for a single target. var commandLine = [self.tool.pathString] commandLine += ["-module-name", module.c99name] - commandLine += try buildParameters.targetTripleArgs(for: module) + commandLine += try buildParameters.tripleArgs(for: module) commandLine += try buildPlan.createAPIToolCommonArgs(includeLibrarySearchPaths: true) commandLine += ["-module-cache-path", try buildParameters.moduleCache.pathString] if verboseOutput { diff --git a/Sources/Commands/Utilities/TestingSupport.swift b/Sources/Commands/Utilities/TestingSupport.swift index 2b2e67ac120..2ba203320b5 100644 --- a/Sources/Commands/Utilities/TestingSupport.swift +++ b/Sources/Commands/Utilities/TestingSupport.swift @@ -36,7 +36,9 @@ enum TestingSupport { func findXCTestHelper(swiftBuildPath: AbsolutePath) -> AbsolutePath? { // XCTestHelper tool is installed in libexec. - let maybePath = swiftBuildPath.parentDirectory.parentDirectory.appending(components: "libexec", "swift", "pm", "swiftpm-xctest-helper") + let maybePath = swiftBuildPath.parentDirectory.parentDirectory.appending( + components: "libexec", "swift", "pm", "swiftpm-xctest-helper" + ) if swiftCommandState.fileSystem.isFile(maybePath) { return maybePath } else { @@ -54,7 +56,10 @@ enum TestingSupport { // This will be true during swiftpm development or when using swift.org toolchains. let xcodePath = try TSCBasic.Process.checkNonZeroExit(args: "/usr/bin/xcode-select", "--print-path").spm_chomp() - let installedSwiftBuildPath = try TSCBasic.Process.checkNonZeroExit(args: "/usr/bin/xcrun", "--find", "swift-build", environment: ["DEVELOPER_DIR": xcodePath]).spm_chomp() + let installedSwiftBuildPath = try TSCBasic.Process.checkNonZeroExit( + args: "/usr/bin/xcrun", "--find", "swift-build", + environment: ["DEVELOPER_DIR": xcodePath] + ).spm_chomp() if let xctestHelperPath = findXCTestHelper(swiftBuildPath: try AbsolutePath(validating: installedSwiftBuildPath)) { return xctestHelperPath } @@ -127,7 +132,7 @@ enum TestingSupport { #else let env = try Self.constructTestEnvironment( toolchain: try swiftCommandState.getTargetToolchain(), - buildParameters: swiftCommandState.buildParametersForTest( + destinationBuildParameters: swiftCommandState.buildParametersForTest( enableCodeCoverage: enableCodeCoverage, shouldSkipBuilding: shouldSkipBuilding, library: .xctest diff --git a/Sources/Commands/Utilities/XCTEvents.swift b/Sources/Commands/Utilities/XCTEvents.swift index a264b205e3a..0ceedfce77f 100644 --- a/Sources/Commands/Utilities/XCTEvents.swift +++ b/Sources/Commands/Utilities/XCTEvents.swift @@ -237,12 +237,12 @@ extension TestErrorInfo { extension TestIssue { init(_ issue: XCTIssue) { self.init( - type: .init(destinationBuildParameters: issue.type), + type: .init(defaultBuildParameters: issue.type), compactDescription: issue.compactDescription, detailedDescription: issue.detailedDescription, - associatedError: issue.associatedError.map { .init(destinationBuildParameters: $0) }, - sourceCodeContext: .init(destinationBuildParameters: issue.sourceCodeContext), - attachments: issue.attachments.map { .init(destinationBuildParameters: $0) } + associatedError: issue.associatedError.map { .init(defaultBuildParameters: $0) }, + sourceCodeContext: .init(defaultBuildParameters: issue.sourceCodeContext), + attachments: issue.attachments.map { .init(defaultBuildParameters: $0) } ) } } @@ -275,8 +275,8 @@ extension TestLocation { extension TestSourceCodeContext { init(_ context: XCTSourceCodeContext) { self.init( - callStack: context.callStack.map { .init(destinationBuildParameters: $0) }, - location: context.location.map { .init(destinationBuildParameters: $0) } + callStack: context.callStack.map { .init(defaultBuildParameters: $0) }, + location: context.location.map { .init(defaultBuildParameters: $0) } ) } } @@ -285,8 +285,8 @@ extension TestSourceCodeFrame { init(_ frame: XCTSourceCodeFrame) { self.init( address: frame.address, - symbolInfo: (try? frame.symbolInfo()).map { .init(destinationBuildParameters: $0) }, - symbolicationError: frame.symbolicationError.map { .init(destinationBuildParameters: $0) } + symbolInfo: (try? frame.symbolInfo()).map { .init(defaultBuildParameters: $0) }, + symbolicationError: frame.symbolicationError.map { .init(defaultBuildParameters: $0) } ) } } @@ -296,7 +296,7 @@ extension TestSourceCodeSymbolInfo { self.init( imageName: symbolInfo.imageName, symbolName: symbolInfo.symbolName, - location: symbolInfo.location.map { .init(destinationBuildParameters: $0) } + location: symbolInfo.location.map { .init(defaultBuildParameters: $0) } ) } } diff --git a/Sources/PackageGraph/BuildTriple.swift b/Sources/PackageGraph/BuildTriple.swift index 4e121a2c7bb..87d2daf21f1 100644 --- a/Sources/PackageGraph/BuildTriple.swift +++ b/Sources/PackageGraph/BuildTriple.swift @@ -10,6 +10,9 @@ // //===----------------------------------------------------------------------===// +import class PackageModel.Target +import class PackageModel.Product + /// Triple for which code should be compiled for. /// > Note: We're not using "host" and "target" triple terminology in this enum, as that clashes with build /// > system "targets" and can lead to confusion in this context. @@ -20,3 +23,23 @@ public enum BuildTriple { /// Triple of the destination platform for which end products are compiled (the target triple). case destination } + +extension Target { + var buildTriple: BuildTriple { + if self.type == .macro || self.type == .plugin { + .tools + } else { + .destination + } + } +} + +extension Product { + var buildTriple: BuildTriple { + if self.type == .macro || self.type == .plugin { + .tools + } else { + .destination + } + } +} diff --git a/Sources/PackageGraph/CMakeLists.txt b/Sources/PackageGraph/CMakeLists.txt index 6a1695a0a4d..b95b1eb9feb 100644 --- a/Sources/PackageGraph/CMakeLists.txt +++ b/Sources/PackageGraph/CMakeLists.txt @@ -35,7 +35,7 @@ add_library(PackageGraph Resolution/PlatformVersionProvider.swift Resolution/ResolvedPackage.swift Resolution/ResolvedProduct.swift - Resolution/ResolvedTarget.swift + Resolution/ResolvedModule.swift Version+Extensions.swift VersionSetSpecifier.swift) target_link_libraries(PackageGraph PUBLIC diff --git a/Sources/PackageGraph/ModulesGraph+Loading.swift b/Sources/PackageGraph/ModulesGraph+Loading.swift index a324b283e95..4b0dbb57a3b 100644 --- a/Sources/PackageGraph/ModulesGraph+Loading.swift +++ b/Sources/PackageGraph/ModulesGraph+Loading.swift @@ -197,16 +197,16 @@ private func checkAllDependenciesAreUsed( ) { for package in rootPackages { // List all dependency products dependent on by the package targets. - let productDependencies = IdentifiableSet(package.targets.flatMap({ target in - return target.dependencies.compactMap({ targetDependency in + let productDependencies = IdentifiableSet(package.targets.flatMap { target in + return target.dependencies.compactMap { targetDependency in switch targetDependency { case .product(let product, _): return product case .target: return nil } - }) - })) + } + }) for dependencyId in package.dependencies { guard let dependency = packages[dependencyId] else { @@ -239,7 +239,12 @@ private func checkAllDependenciesAreUsed( ) // Otherwise emit a warning if none of the dependency package's products are used. - let dependencyIsUsed = dependency.products.contains(where: { productDependencies.contains(id: $0.id) }) + let dependencyIsUsed = dependency.products.contains { product in + // Don't compare by product ID, but by product name to make sure both build triples as properties of + // `ResolvedProduct.ID` are allowed. + productDependencies.contains { $0.name == product.name } + } + if !dependencyIsUsed && !observabilityScope.errorsReportedInAnyScope { packageDiagnosticsScope.emit(.unusedDependency(dependency.identity.description)) } @@ -297,7 +302,10 @@ private func createResolvedPackages( // Resolve module aliases, if specified, for targets and their dependencies // across packages. Aliasing will result in target renaming. - let moduleAliasingUsed = try resolveModuleAliases(packageBuilders: packageBuilders, observabilityScope: observabilityScope) + let moduleAliasingUsed = try resolveModuleAliases( + packageBuilders: packageBuilders, + observabilityScope: observabilityScope + ) // Scan and validate the dependencies for packageBuilder in packageBuilders { @@ -662,7 +670,7 @@ private func createResolvedPackages( observabilityScope.emit( ModuleError.duplicateModule( targetName: entry.key, - packages: entry.value.map{ $0.identity }) + packages: entry.value.map { $0.identity }) ) } } @@ -1003,7 +1011,7 @@ private final class ResolvedTargetBuilder: ResolvedBuilder { } } - return ResolvedTarget( + return ResolvedModule( packageIdentity: self.packageIdentity, underlying: self.target, dependencies: dependencies, diff --git a/Sources/PackageGraph/ModulesGraph.swift b/Sources/PackageGraph/ModulesGraph.swift index 2af4f421e54..1c5b2fa78f0 100644 --- a/Sources/PackageGraph/ModulesGraph.swift +++ b/Sources/PackageGraph/ModulesGraph.swift @@ -65,13 +65,13 @@ public struct ModulesGraph { public let packages: IdentifiableSet /// The list of all targets reachable from root targets. - public let reachableTargets: IdentifiableSet + public private(set) var reachableTargets: IdentifiableSet /// The list of all products reachable from root targets. - public let reachableProducts: IdentifiableSet + public private(set) var reachableProducts: IdentifiableSet /// Returns all the targets in the graph, regardless if they are reachable from the root targets or not. - public let allTargets: IdentifiableSet + public private(set) var allTargets: IdentifiableSet /// Returns all targets within the module graph in topological order, starting with low-level targets (that have no /// dependencies). @@ -82,8 +82,7 @@ public struct ModulesGraph { } /// Returns all the products in the graph, regardless if they are reachable from the root targets or not. - - public let allProducts: IdentifiableSet + public private(set) var allProducts: IdentifiableSet /// Package dependencies required for a fully resolved graph. /// @@ -94,10 +93,14 @@ public struct ModulesGraph { /// Returns true if a given target is present in root packages and is not excluded for the given build environment. public func isInRootPackages(_ target: ResolvedModule, satisfying buildEnvironment: BuildEnvironment) -> Bool { // FIXME: This can be easily cached. - return rootPackages.reduce(into: IdentifiableSet()) { (accumulator: inout IdentifiableSet, package: ResolvedPackage) in + return rootPackages.reduce( + into: IdentifiableSet() + ) { (accumulator: inout IdentifiableSet, package: ResolvedPackage) in let allDependencies = package.targets.flatMap { $0.dependencies } let unsatisfiedDependencies = allDependencies.filter { !$0.satisfies(buildEnvironment) } - let unsatisfiedDependencyTargets = unsatisfiedDependencies.compactMap { (dep: ResolvedModule.Dependency) -> ResolvedModule? in + let unsatisfiedDependencyTargets = unsatisfiedDependencies.compactMap { ( + dep: ResolvedModule.Dependency + ) -> ResolvedModule? in switch dep { case .target(let target, _): return target @@ -155,29 +158,46 @@ public struct ModulesGraph { self.binaryArtifacts = binaryArtifacts self.packages = packages - let allTargets = IdentifiableSet(packages.flatMap({ package -> [ResolvedModule] in + var allTargets = IdentifiableSet() + var allProducts = IdentifiableSet() + for package in self.packages { + let targetsToInclude: [ResolvedModule] if rootPackages.contains(id: package.id) { - return package.targets + targetsToInclude = Array(package.targets) } else { // Don't include tests targets from non-root packages so swift-test doesn't // try to run them. - return package.targets.filter({ $0.type != .test }) + targetsToInclude = package.targets.filter { $0.type != .test } + } + + for target in targetsToInclude { + allTargets.insert(target) + + // Explicitly include dependencies of host tools in the maps of all targets or all products + if target.buildTriple == .tools { + for dependency in try target.recursiveDependencies() { + switch dependency { + case .target(let targetDependency, _): + allTargets.insert(targetDependency) + case .product(let productDependency, _): + allProducts.insert(productDependency) + } + } + } } - })) - let allProducts = IdentifiableSet(packages.flatMap({ package -> [ResolvedProduct] in if rootPackages.contains(id: package.id) { - return package.products + allProducts.formUnion(package.products) } else { - // Don't include tests products from non-root packages so swift-test doesn't + // Don't include test products from non-root packages so swift-test doesn't // try to run them. - return package.products.filter({ $0.type != .test }) + allProducts.formUnion(package.products.filter { $0.type != .test }) } - })) + } // Compute the reachable targets and products. - let inputTargets = inputPackages.flatMap { $0.targets } - let inputProducts = inputPackages.flatMap { $0.products } + let inputTargets = self.inputPackages.flatMap { $0.targets } + let inputProducts = self.inputPackages.flatMap { $0.products } let recursiveDependencies = try inputTargets.lazy.flatMap { try $0.recursiveDependencies() } self.reachableTargets = IdentifiableSet(inputTargets).union(recursiveDependencies.compactMap { $0.target }) @@ -187,6 +207,30 @@ public struct ModulesGraph { self.allProducts = allProducts } + package mutating func updateBuildTripleRecursively(_ buildTriple: BuildTriple) throws { + self.reachableTargets = IdentifiableSet(self.reachableTargets.map { + var target = $0 + target.buildTriple = buildTriple + return target + }) + self.reachableProducts = IdentifiableSet(self.reachableProducts.map { + var product = $0 + product.buildTriple = buildTriple + return product + }) + + self.allTargets = IdentifiableSet(self.allTargets.map { + var target = $0 + target.buildTriple = buildTriple + return target + }) + self.allProducts = IdentifiableSet(self.allProducts.map { + var product = $0 + product.buildTriple = buildTriple + return product + }) + } + /// Computes a map from each executable target in any of the root packages to the corresponding test targets. func computeTestTargetsForExecutableTargets() throws -> [ResolvedModule.ID: [ResolvedModule]] { var result = [ResolvedModule.ID: [ResolvedModule]]() diff --git a/Sources/PackageGraph/Resolution/ResolvedTarget.swift b/Sources/PackageGraph/Resolution/ResolvedModule.swift similarity index 78% rename from Sources/PackageGraph/Resolution/ResolvedTarget.swift rename to Sources/PackageGraph/Resolution/ResolvedModule.swift index b8854a8ba3b..f218a35886d 100644 --- a/Sources/PackageGraph/Resolution/ResolvedTarget.swift +++ b/Sources/PackageGraph/Resolution/ResolvedModule.swift @@ -136,7 +136,7 @@ public struct ResolvedModule { public let underlying: Target /// The dependencies of this target. - public let dependencies: [Dependency] + public internal(set) var dependencies: [Dependency] /// The default localization for resources. public let defaultLocalization: String? @@ -147,7 +147,11 @@ public struct ResolvedModule { private let platformVersionProvider: PlatformVersionProvider /// Triple for which this resolved target should be compiled for. - public let buildTriple: BuildTriple + public package(set) var buildTriple: BuildTriple { + didSet { + self.updateBuildTriplesOfDependencies() + } + } /// Create a resolved target instance. public init( @@ -164,7 +168,50 @@ public struct ResolvedModule { self.defaultLocalization = defaultLocalization self.supportedPlatforms = supportedPlatforms self.platformVersionProvider = platformVersionProvider - self.buildTriple = .destination + + if underlying.type == .test { + // Make sure that test products are built for the tools triple if it has tools as direct dependencies. + // Without this workaround, `assertMacroExpansion` in tests can't be built, as it requires macros + // and SwiftSyntax to be built for the same triple as the tests. + // See https://github.com/apple/swift-package-manager/pull/7349 for more context. + var inferredBuildTriple = BuildTriple.destination + loop: for dependency in dependencies { + switch dependency { + case .target(let targetDependency, _): + if targetDependency.type == .macro { + inferredBuildTriple = .tools + break loop + } + case .product(let productDependency, _): + if productDependency.type == .macro { + inferredBuildTriple = .tools + break loop + } + } + } + self.buildTriple = inferredBuildTriple + } else { + self.buildTriple = underlying.buildTriple + } + self.updateBuildTriplesOfDependencies() + } + + mutating func updateBuildTriplesOfDependencies() { + if self.buildTriple == .tools { + for (i, dependency) in dependencies.enumerated() { + let updatedDependency: Dependency + switch dependency { + case .target(var target, let conditions): + target.buildTriple = self.buildTriple + updatedDependency = .target(target, conditions: conditions) + case .product(var product, let conditions): + product.buildTriple = self.buildTriple + updatedDependency = .product(product, conditions: conditions) + } + + dependencies[i] = updatedDependency + } + } } public func getSupportedPlatform(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform { @@ -178,13 +225,13 @@ public struct ResolvedModule { extension ResolvedModule: CustomStringConvertible { public var description: String { - return "" + return "" } } extension ResolvedModule.Dependency: CustomStringConvertible { public var description: String { - var str = " + public internal(set) var targets: IdentifiableSet /// Executable target for test entry point file. public let testEntryPointTarget: ResolvedModule? @@ -44,7 +44,11 @@ public struct ResolvedProduct { public let platformVersionProvider: PlatformVersionProvider /// Triple for which this resolved product should be compiled for. - public let buildTriple: BuildTriple + public internal(set) var buildTriple: BuildTriple { + didSet { + self.updateBuildTriplesOfDependencies() + } + } /// The main executable target of product. /// @@ -63,7 +67,11 @@ public struct ResolvedProduct { } } - public init(packageIdentity: PackageIdentity, product: Product, targets: IdentifiableSet) { + public init( + packageIdentity: PackageIdentity, + product: Product, + targets: IdentifiableSet + ) { assert(product.targets.count == targets.count && product.targets.map(\.name).sorted() == targets.map(\.name).sorted()) self.packageIdentity = packageIdentity self.underlying = product @@ -97,7 +105,41 @@ public struct ResolvedProduct { ) } - self.buildTriple = .destination + if product.type == .test { + // Make sure that test products are built for the tools triple if it has tools as direct dependencies. + // Without this workaround, `assertMacroExpansion` in tests can't be built, as it requires macros + // and SwiftSyntax to be built for the same triple as the tests. + // See https://github.com/apple/swift-package-manager/pull/7349 for more context. + var inferredBuildTriple = BuildTriple.destination + targetsLoop: for target in targets { + for dependency in target.dependencies { + switch dependency { + case .target(let targetDependency, _): + if targetDependency.type == .macro { + inferredBuildTriple = .tools + break targetsLoop + } + case .product(let productDependency, _): + if productDependency.type == .macro { + inferredBuildTriple = .tools + break targetsLoop + } + } + } + } + self.buildTriple = inferredBuildTriple + } else { + self.buildTriple = product.buildTriple + } + self.updateBuildTriplesOfDependencies() + } + + mutating func updateBuildTriplesOfDependencies() { + self.targets = IdentifiableSet(self.targets.map { + var target = $0 + target.buildTriple = self.buildTriple + return target + }) } /// True if this product contains Swift targets. @@ -151,7 +193,7 @@ public struct ResolvedProduct { extension ResolvedProduct: CustomStringConvertible { public var description: String { - "" + "" } } @@ -166,13 +208,13 @@ extension ResolvedProduct { extension ResolvedProduct: Identifiable { /// Resolved target identity that uniquely identifies it in a resolution graph. public struct ID: Hashable { - public let targetName: String + public let productName: String let packageIdentity: PackageIdentity - public let buildTriple: BuildTriple + public var buildTriple: BuildTriple } public var id: ID { - ID(targetName: self.name, packageIdentity: self.packageIdentity, buildTriple: self.buildTriple) + ID(productName: self.name, packageIdentity: self.packageIdentity, buildTriple: self.buildTriple) } } diff --git a/Sources/PackageModel/Target/Target.swift b/Sources/PackageModel/Target/Target.swift index c49b93ba142..b66e5159fa7 100644 --- a/Sources/PackageModel/Target/Target.swift +++ b/Sources/PackageModel/Target/Target.swift @@ -131,7 +131,7 @@ public class Target: PolymorphicCodableProtocol { /// The name of the target. /// /// NOTE: This name is not the language-level target (i.e., the importable - /// name) name in many cases, instead use c99name if you need uniqueness. + /// name) name in many cases, instead use ``Target/c99name`` if you need uniqueness. public private(set) var name: String /// Module aliases needed to build this target. The key is an original name of a diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index e81e99e242f..02902339324 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -248,7 +248,7 @@ public struct BuildParameters: Encodable { /// Returns the path to the binary of a product for the current build parameters, relative to the build directory. public func binaryRelativePath(for product: ResolvedProduct) throws -> RelativePath { - let potentialExecutablePath = try RelativePath(validating: "\(product.name)\(self.triple.executableExtension)") + let potentialExecutablePath = try RelativePath(validating: "\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.executableExtension)") switch product.type { case .executable, .snippet: @@ -329,3 +329,11 @@ extension Triple { return !self.isWindows() } } + +extension BuildParameters { + /// Suffix appended to build manifest nodes to distinguish nodes created for tools from nodes created for + /// end products, i.e. nodes for host vs target triples. + package func suffix(triple: BuildTriple) -> String { + if triple == .tools { "-tool" } else { "" } + } +} diff --git a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift index 9576c25a8aa..5bdd8a35470 100644 --- a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift +++ b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift @@ -74,7 +74,7 @@ extension ProductBuildDescription { /// The path to the product binary produced. public var binaryPath: AbsolutePath { get throws { - return try self.buildParameters.binaryPath(for: product) + try self.buildParameters.binaryPath(for: product) } } } diff --git a/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift b/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift index 2c8562f6f4a..cdbb9735655 100644 --- a/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift +++ b/Sources/SPMBuildCore/Plugins/PluginContextSerializer.swift @@ -56,7 +56,7 @@ internal struct PluginContextSerializer { // Adds a target to the serialized structure, if it isn't already there and // if it is of a kind that should be passed to the plugin. If so, this func- // tion returns the target's wire ID. If not, it returns nil. - mutating func serialize(target: ResolvedTarget) throws -> WireInput.Target.Id? { + mutating func serialize(target: ResolvedModule) throws -> WireInput.Target.Id? { // If we've already seen the target, just return the wire ID we already assigned to it. if let id = targetsToWireIDs[target.id] { return id } diff --git a/Sources/SPMBuildCore/Plugins/PluginInvocation.swift b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift index 235b89a116c..3ab08cd47d5 100644 --- a/Sources/SPMBuildCore/Plugins/PluginInvocation.swift +++ b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift @@ -402,8 +402,8 @@ extension ModulesGraph { observabilityScope: ObservabilityScope, fileSystem: FileSystem, builtToolHandler: (_ name: String, _ path: RelativePath) throws -> AbsolutePath? = { _, _ in return nil } - ) throws -> [ResolvedTarget.ID: (target: ResolvedTarget, results: [BuildToolPluginInvocationResult])] { - var pluginResultsByTarget: [ResolvedTarget.ID: (target: ResolvedTarget, results: [BuildToolPluginInvocationResult])] = [:] + ) throws -> [ResolvedModule.ID: (target: ResolvedModule, results: [BuildToolPluginInvocationResult])] { + var pluginResultsByTarget: [ResolvedModule.ID: (target: ResolvedModule, results: [BuildToolPluginInvocationResult])] = [:] for target in self.allTargets.sorted(by: { $0.name < $1.name }) { // Infer plugins from the declared dependencies, and collect them as well as any regular dependencies. Although usage of build tool plugins is declared separately from dependencies in the manifest, in the internal model we currently consider both to be dependencies. var pluginTargets: [PluginTarget] = [] @@ -597,13 +597,15 @@ extension ModulesGraph { } // Associate the list of results with the target. The list will have one entry for each plugin used by the target. - pluginResultsByTarget[target.id] = (target, buildToolPluginResults) + var targetID = target.id + targetID.buildTriple = .destination + pluginResultsByTarget[targetID] = (target, buildToolPluginResults) } return pluginResultsByTarget } public static func computePluginGeneratedFiles( - target: ResolvedTarget, + target: ResolvedModule, toolsVersion: ToolsVersion, additionalFileRules: [FileRuleDescription], buildParameters: BuildParameters, @@ -749,7 +751,7 @@ public struct BuildToolPluginInvocationResult { public var package: ResolvedPackage /// The target in that package to which the plugin was applied. - public var target: ResolvedTarget + public var target: ResolvedModule /// If the plugin finished successfully. public var succeeded: Bool diff --git a/Sources/SPMTestSupport/MockArchiver.swift b/Sources/SPMTestSupport/MockArchiver.swift index cf1a84434df..296f0d413a9 100644 --- a/Sources/SPMTestSupport/MockArchiver.swift +++ b/Sources/SPMTestSupport/MockArchiver.swift @@ -12,7 +12,7 @@ import Basics -package class MockArchiver: Archiver { +package final class MockArchiver: Archiver { package typealias ExtractionHandler = ( MockArchiver, AbsolutePath, diff --git a/Sources/SPMTestSupport/MockBuildTestHelper.swift b/Sources/SPMTestSupport/MockBuildTestHelper.swift index 83662600628..92a4dcb0328 100644 --- a/Sources/SPMTestSupport/MockBuildTestHelper.swift +++ b/Sources/SPMTestSupport/MockBuildTestHelper.swift @@ -15,6 +15,8 @@ import Basics @_spi(SwiftPMInternal) import Build +import struct PackageGraph.ResolvedModule +import struct PackageGraph.ResolvedProduct import PackageModel import SPMBuildCore import TSCUtility @@ -31,7 +33,7 @@ public struct MockToolchain: PackageModel.Toolchain { public let swiftCompilerPath = AbsolutePath("/fake/path/to/swiftc") public let includeSearchPaths = [AbsolutePath]() public let librarySearchPaths = [AbsolutePath]() - public let swiftResourcesPath: AbsolutePath? = nil + public let swiftResourcesPath: AbsolutePath? public let swiftStaticResourcesPath: AbsolutePath? = nil public let sdkRootPath: AbsolutePath? = nil public let extraFlags = PackageModel.BuildFlags() @@ -50,7 +52,9 @@ public struct MockToolchain: PackageModel.Toolchain { #endif } - public init() {} + public init(swiftResourcesPath: AbsolutePath? = nil) { + self.swiftResourcesPath = swiftResourcesPath + } } extension Basics.Triple { @@ -70,15 +74,15 @@ public let defaultTargetTriple: String = hostTriple.tripleString(forPlatformVers public let defaultTargetTriple: String = hostTriple.tripleString #endif -public func mockBuildParameters( - buildPath: AbsolutePath = "/path/to/build", +package func mockBuildParameters( + buildPath: AbsolutePath? = nil, config: BuildConfiguration = .debug, toolchain: PackageModel.Toolchain = MockToolchain(), flags: PackageModel.BuildFlags = PackageModel.BuildFlags(), shouldLinkStaticSwiftStdlib: Bool = false, shouldDisableLocalRpath: Bool = false, canRenameEntrypointFunctionName: Bool = false, - targetTriple: Basics.Triple = hostTriple, + triple: Basics.Triple = hostTriple, indexStoreMode: BuildParameters.IndexStoreMode = .off, useExplicitModuleBuild: Bool = false, linkerDeadStrip: Bool = true, @@ -86,16 +90,16 @@ public func mockBuildParameters( omitFramePointers: Bool? = nil ) -> BuildParameters { try! BuildParameters( - dataPath: buildPath, + dataPath: buildPath ?? AbsolutePath("/path/to/build").appending(triple.tripleString), configuration: config, toolchain: toolchain, - triple: targetTriple, + triple: triple, flags: flags, pkgConfigDirectories: [], workers: 3, indexStoreMode: indexStoreMode, debuggingParameters: .init( - triple: targetTriple, + triple: triple, shouldEnableDebuggingEntitlement: config == .debug, omitFramePointers: omitFramePointers ), @@ -127,24 +131,24 @@ public func mockBuildParameters(environment: BuildEnvironment) -> BuildParameter fatalError("unsupported platform in tests") } - return mockBuildParameters(config: environment.configuration ?? .debug, targetTriple: triple) + return mockBuildParameters(config: environment.configuration ?? .debug, triple: triple) } enum BuildError: Swift.Error { case error(String) } -public struct BuildPlanResult { - public let plan: Build.BuildPlan - public let targetMap: [String: TargetBuildDescription] - public let productMap: [String: Build.ProductBuildDescription] +package struct BuildPlanResult { + package let plan: Build.BuildPlan + package let targetMap: [ResolvedModule.ID: TargetBuildDescription] + package let productMap: [ResolvedProduct.ID: Build.ProductBuildDescription] public init(plan: Build.BuildPlan) throws { self.plan = plan self.productMap = try Dictionary( throwingUniqueKeysWithValues: plan.buildProducts .compactMap { $0 as? Build.ProductBuildDescription } - .map { ($0.product.name, $0) } + .map { ($0.product.id, $0) } ) self.targetMap = try Dictionary( throwingUniqueKeysWithValues: plan.targetMap.compactMap { @@ -154,7 +158,7 @@ public struct BuildPlanResult { else { throw BuildError.error("Target \($0) not found.") } - return (target.name, $1) + return (target.id, $1) } ) } @@ -167,17 +171,27 @@ public struct BuildPlanResult { XCTAssertEqual(self.plan.productMap.count, count, file: file, line: line) } - public func target(for name: String) throws -> TargetBuildDescription { - guard let target = targetMap[name] else { - throw BuildError.error("Target \(name) not found.") + package func target(for name: String) throws -> TargetBuildDescription { + let matchingIDs = targetMap.keys.filter({ $0.targetName == name }) + guard matchingIDs.count == 1, let target = targetMap[matchingIDs[0]] else { + if matchingIDs.isEmpty { + throw BuildError.error("Target \(name) not found.") + } else { + throw BuildError.error("More than one target \(name) found.") + } } return target } - public func buildProduct(for name: String) throws -> Build.ProductBuildDescription { - guard let product = productMap[name] else { - // Display the thrown error on macOS - throw BuildError.error("Product \(name) not found.") + package func buildProduct(for name: String) throws -> Build.ProductBuildDescription { + let matchingIDs = productMap.keys.filter({ $0.productName == name }) + guard matchingIDs.count == 1, let product = productMap[matchingIDs[0]] else { + if matchingIDs.isEmpty { + // Display the thrown error on macOS + throw BuildError.error("Product \(name) not found.") + } else { + throw BuildError.error("More than one target \(name) found.") + } } return product } diff --git a/Sources/SPMTestSupport/MockPackageGraphs.swift b/Sources/SPMTestSupport/MockPackageGraphs.swift index 4ab9c0cde98..1f3f956e23a 100644 --- a/Sources/SPMTestSupport/MockPackageGraphs.swift +++ b/Sources/SPMTestSupport/MockPackageGraphs.swift @@ -20,15 +20,13 @@ import struct PackageModel.TargetDescription import protocol TSCBasic.FileSystem import class TSCBasic.InMemoryFileSystem -@_spi(SwiftPMInternal) -public typealias MockPackageGraph = ( +package typealias MockPackageGraph = ( graph: ModulesGraph, fileSystem: any FileSystem, observabilityScope: ObservabilityScope ) -@_spi(SwiftPMInternal) -public func macrosPackageGraph() throws -> MockPackageGraph { +package func macrosPackageGraph() throws -> MockPackageGraph { let fs = InMemoryFileSystem(emptyFiles: "/swift-firmware/Sources/Core/source.swift", "/swift-firmware/Sources/HAL/source.swift", @@ -41,7 +39,7 @@ public func macrosPackageGraph() throws -> MockPackageGraph { ) let observability = ObservabilitySystem.makeForTesting() - let graph = try loadPackageGraph( + let graph = try loadModulesGraph( fileSystem: fs, manifests: [ Manifest.createRootManifest( @@ -126,8 +124,136 @@ public func macrosPackageGraph() throws -> MockPackageGraph { return (graph, fs, observability.topScope) } -@_spi(SwiftPMInternal) -public func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { +package func macrosTestsPackageGraph() throws -> MockPackageGraph { + let fs = InMemoryFileSystem(emptyFiles: + "/swift-mmio/Sources/MMIO/source.swift", + "/swift-mmio/Sources/MMIOMacros/source.swift", + "/swift-mmio/Sources/MMIOMacrosTests/source.swift", + "/swift-syntax/Sources/SwiftSyntax/source.swift", + "/swift-syntax/Sources/SwiftSyntaxMacrosTestSupport/source.swift", + "/swift-syntax/Sources/SwiftSyntaxMacros/source.swift", + "/swift-syntax/Sources/SwiftCompilerPlugin/source.swift", + "/swift-syntax/Sources/SwiftCompilerPluginMessageHandling/source.swift", + "/swift-syntax/Tests/SwiftSyntaxTests/source.swift" + ) + + let observability = ObservabilitySystem.makeForTesting() + let graph = try loadModulesGraph( + fileSystem: fs, + manifests: [ + Manifest.createRootManifest( + displayName: "swift-mmio", + path: "/swift-mmio", + dependencies: [ + .localSourceControl( + path: "/swift-syntax", + requirement: .upToNextMajor(from: "1.0.0") + ) + ], + products: [ + ProductDescription( + name: "MMIO", + type: .library(.automatic), + targets: ["MMIO"] + ) + ], + targets: [ + TargetDescription( + name: "MMIO", + dependencies: [.target(name: "MMIOMacros")] + ), + TargetDescription( + name: "MMIOMacros", + dependencies: [ + .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), + .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), + ], + type: .macro + ), + TargetDescription( + name: "MMIOMacrosTests", + dependencies: [ + .target(name: "MMIOMacros"), + .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax") + ], + type: .test + ) + ] + ), + Manifest.createFileSystemManifest( + displayName: "swift-syntax", + path: "/swift-syntax", + products: [ + ProductDescription( + name: "SwiftSyntaxMacros", + type: .library(.automatic), + targets: ["SwiftSyntax"] + ), + ProductDescription( + name: "SwiftSyntax", + type: .library(.automatic), + targets: ["SwiftSyntax"] + ), + ProductDescription( + name: "SwiftSyntaxMacrosTestSupport", + type: .library(.automatic), + targets: ["SwiftSyntaxMacrosTestSupport"] + ), + ProductDescription( + name: "SwiftCompilerPlugin", + type: .library(.automatic), + targets: ["SwiftCompilerPlugin"] + ), + ProductDescription( + name: "SwiftCompilerPluginMessageHandling", + type: .library(.automatic), + targets: ["SwiftCompilerPluginMessageHandling"] + ), + ], + targets: [ + TargetDescription( + name: "SwiftSyntax", + dependencies: [] + ), + TargetDescription( + name: "SwiftSyntaxMacros", + dependencies: [.target(name: "SwiftSyntax")] + ), + TargetDescription( + name: "SwiftCompilerPlugin", + dependencies: [ + .target(name: "SwiftCompilerPluginMessageHandling"), + .target(name: "SwiftSyntaxMacros"), + ] + ), + TargetDescription( + name: "SwiftCompilerPluginMessageHandling", + dependencies: [ + .target(name: "SwiftSyntax"), + .target(name: "SwiftSyntaxMacros"), + ] + ), + TargetDescription( + name: "SwiftSyntaxMacrosTestSupport", + dependencies: [.target(name: "SwiftSyntax")] + ), + TargetDescription( + name: "SwiftSyntaxTests", + dependencies: ["SwiftSyntax"], + type: .test + ), + ] + ), + ], + observabilityScope: observability.topScope + ) + + XCTAssertNoDiagnostics(observability.diagnostics) + + return (graph, fs, observability.topScope) +} + +package func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { let fs = InMemoryFileSystem( emptyFiles: "/Pkg/Sources/app/main.swift", @@ -137,7 +263,7 @@ public func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackage ) let observability = ObservabilitySystem.makeForTesting() - let graph = try loadPackageGraph( + let graph = try loadModulesGraph( fileSystem: fs, manifests: [ Manifest.createRootManifest( @@ -157,8 +283,7 @@ public func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackage return (graph, fs, observability.topScope) } -@_spi(SwiftPMInternal) -public func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { +package func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { let fs = InMemoryFileSystem( emptyFiles: "/Pkg/Sources/app/main.swift", @@ -168,7 +293,7 @@ public func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> ) let observability = ObservabilitySystem.makeForTesting() - let graph = try loadPackageGraph( + let graph = try loadModulesGraph( fileSystem: fs, manifests: [ Manifest.createRootManifest( diff --git a/Sources/SPMTestSupport/PackageGraphTester.swift b/Sources/SPMTestSupport/PackageGraphTester.swift index 97aa593a971..d6db67d74a5 100644 --- a/Sources/SPMTestSupport/PackageGraphTester.swift +++ b/Sources/SPMTestSupport/PackageGraphTester.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift open source project // -// Copyright (c) 2014-2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,8 +17,8 @@ import struct Basics.IdentifiableSet import PackageModel import PackageGraph -public func PackageGraphTester(_ graph: ModulesGraph, _ result: (PackageGraphResult) -> Void) { - result(PackageGraphResult(graph)) +package func PackageGraphTester(_ graph: ModulesGraph, _ result: (PackageGraphResult) throws -> Void) rethrows { + try result(PackageGraphResult(graph)) } public final class PackageGraphResult { @@ -49,8 +49,8 @@ public final class PackageGraphResult { public func check(targets: String..., file: StaticString = #file, line: UInt = #line) { XCTAssertEqual( graph.allTargets - .filter{ $0.type != .test } - .map{ $0.name } + .filter { $0.type != .test } + .map { $0.name } .sorted(), targets.sorted(), file: file, line: line) } @@ -86,16 +86,30 @@ public final class PackageGraphResult { XCTAssertEqual(products, Set(reachableBuildProducts), file: file, line: line) } - public func checkTarget( + package func checkTarget( _ name: String, file: StaticString = #file, line: UInt = #line, body: (ResolvedTargetResult) -> Void ) { - guard let target = find(target: name) else { + let targets = find(target: name) + + guard targets.count > 0 else { return XCTFail("Target \(name) not found", file: file, line: line) } - body(ResolvedTargetResult(target)) + guard targets.count == 1 else { + return XCTFail("More than a single target with name \(name) found", file: file, line: line) + } + body(ResolvedTargetResult(targets[0])) + } + + package func checkTargets( + _ name: String, + file: StaticString = #file, + line: UInt = #line, + body: ([ResolvedTargetResult]) throws -> Void + ) rethrows { + try body(graph.allTargets.filter { $0.name == name }.map(ResolvedTargetResult.init)) } public func checkProduct( @@ -104,10 +118,16 @@ public final class PackageGraphResult { line: UInt = #line, body: (ResolvedProductResult) -> Void ) { - guard let target = find(product: name) else { + let products = find(product: name) + + guard products.count > 0 else { return XCTFail("Product \(name) not found", file: file, line: line) } - body(ResolvedProductResult(target)) + + guard products.count == 1 else { + return XCTFail("More than a single product with name \(name) found", file: file, line: line) + } + body(ResolvedProductResult(products[0])) } public func check(testModules: String..., file: StaticString = #file, line: UInt = #line) { @@ -118,19 +138,19 @@ public final class PackageGraphResult { .sorted(), testModules.sorted(), file: file, line: line) } - public func find(target: String) -> ResolvedTarget? { - return graph.allTargets.first(where: { $0.name == target }) + package func find(target: String) -> [ResolvedModule] { + return graph.allTargets.filter { $0.name == target } } - public func find(product: String) -> ResolvedProduct? { - return graph.allProducts.first(where: { $0.name == product }) + package func find(product: String) -> [ResolvedProduct] { + return graph.allProducts.filter { $0.name == product } } public func find(package: PackageIdentity) -> ResolvedPackage? { return graph.packages.first(where: { $0.identity == package }) } - private func reachableBuildTargets(in environment: BuildEnvironment) throws -> IdentifiableSet { + private func reachableBuildTargets(in environment: BuildEnvironment) throws -> IdentifiableSet { let inputTargets = graph.inputPackages.lazy.flatMap { $0.targets } let recursiveBuildTargetDependencies = try inputTargets .flatMap { try $0.recursiveDependencies(satisfying: environment) } @@ -148,10 +168,10 @@ public final class PackageGraphResult { } } -public final class ResolvedTargetResult { - private let target: ResolvedTarget +package final class ResolvedTargetResult { + let target: ResolvedModule - init(_ target: ResolvedTarget) { + init(_ target: ResolvedModule) { self.target = target } @@ -159,7 +179,11 @@ public final class ResolvedTargetResult { XCTAssertEqual(Set(dependencies), Set(target.dependencies.map({ $0.name })), file: file, line: line) } - public func checkDependency( + package func check(dependencies: [String], file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(Set(dependencies), Set(target.dependencies.map({ $0.name })), file: file, line: line) + } + + package func checkDependency( _ name: String, file: StaticString = #file, line: UInt = #line, @@ -175,8 +199,10 @@ public final class ResolvedTargetResult { XCTAssertEqual(type, target.type, file: file, line: line) } - public func checkDeclaredPlatforms(_ platforms: [String: String], file: StaticString = #file, line: UInt = #line) { - let targetPlatforms = Dictionary(uniqueKeysWithValues: target.supportedPlatforms.map({ ($0.platform.name, $0.version.versionString) })) + package func checkDeclaredPlatforms(_ platforms: [String: String], file: StaticString = #file, line: UInt = #line) { + let targetPlatforms = Dictionary( + uniqueKeysWithValues: target.supportedPlatforms.map { ($0.platform.name, $0.version.versionString) } + ) XCTAssertEqual(platforms, targetPlatforms, file: file, line: line) } @@ -187,22 +213,30 @@ public final class ResolvedTargetResult { return self.target.getSupportedPlatform(for: platform, usingXCTest: self.target.type == .test) } let targetPlatforms = Dictionary( - uniqueKeysWithValues: derived - .map { ($0.platform.name, $0.version.versionString) } + uniqueKeysWithValues: derived.map { ($0.platform.name, $0.version.versionString) } ) XCTAssertEqual(platforms, targetPlatforms, file: file, line: line) } - public func checkDerivedPlatformOptions(_ platform: PackageModel.Platform, options: [String], file: StaticString = #file, line: UInt = #line) { - let platform = target.getSupportedPlatform(for: platform, usingXCTest: target.type == .test) + package func checkDerivedPlatformOptions( + _ platform: PackageModel.Platform, + options: [String], + file: StaticString = #file, + line: UInt = #line + ) { + let platform = self.target.getSupportedPlatform(for: platform, usingXCTest: target.type == .test) XCTAssertEqual(platform.options, options, file: file, line: line) } + + public func check(buildTriple: BuildTriple, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(self.target.buildTriple, buildTriple, file: file, line: line) + } } -public final class ResolvedTargetDependencyResult { - private let dependency: ResolvedTarget.Dependency +package final class ResolvedTargetDependencyResult { + private let dependency: ResolvedModule.Dependency - init(_ dependency: ResolvedTarget.Dependency) { + init(_ dependency: ResolvedModule.Dependency) { self.dependency = dependency } @@ -217,6 +251,28 @@ public final class ResolvedTargetDependencyResult { ) { XCTAssert(!dependency.conditions.allSatisfy({ $0.satisfies(environment) }), file: file, line: line) } + + public func checkTarget( + file: StaticString = #file, + line: UInt = #line, + body: (ResolvedTargetResult) -> Void + ) { + guard case let .target(target, _) = self.dependency else { + return XCTFail("Dependency \(dependency) is not a target", file: file, line: line) + } + body(ResolvedTargetResult(target)) + } + + public func checkProduct( + file: StaticString = #file, + line: UInt = #line, + body: (ResolvedProductResult) -> Void + ) { + guard case let .product(product, _) = self.dependency else { + return XCTFail("Dependency \(dependency) is not a product", file: file, line: line) + } + body(ResolvedProductResult(product)) + } } public final class ResolvedProductResult { @@ -252,10 +308,26 @@ public final class ResolvedProductResult { let platform = product.getSupportedPlatform(for: platform, usingXCTest: product.isLinkingXCTest) XCTAssertEqual(platform.options, options, file: file, line: line) } + + public func check(buildTriple: BuildTriple, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(self.product.buildTriple, buildTriple, file: file, line: line) + } + + package func checkTarget( + _ name: String, + file: StaticString = #file, + line: UInt = #line, + body: (ResolvedTargetResult) -> Void + ) { + guard let target = product.targets.first(where: { $0.name == name }) else { + return XCTFail("Target \(name) not found", file: file, line: line) + } + body(ResolvedTargetResult(target)) + } } -extension ResolvedTarget.Dependency { - public var name: String { +extension ResolvedModule.Dependency { + package var name: String { switch self { case .target(let target, _): return target.name diff --git a/Sources/SPMTestSupport/ResolvedTarget+Mock.swift b/Sources/SPMTestSupport/ResolvedTarget+Mock.swift index 0fa4d373a54..61ddb1cf7b8 100644 --- a/Sources/SPMTestSupport/ResolvedTarget+Mock.swift +++ b/Sources/SPMTestSupport/ResolvedTarget+Mock.swift @@ -13,14 +13,14 @@ import PackageGraph import PackageModel -extension ResolvedTarget { - public static func mock( +extension ResolvedModule { + package static func mock( packageIdentity: PackageIdentity, name: String, - deps: ResolvedTarget..., + deps: ResolvedModule..., conditions: [PackageCondition] = [] - ) -> ResolvedTarget { - ResolvedTarget( + ) -> ResolvedModule { + ResolvedModule( packageIdentity: packageIdentity, underlying: SwiftTarget( name: name, diff --git a/Tests/BuildTests/BuildOperationTests.swift b/Tests/BuildTests/BuildOperationTests.swift index 3f196dd41fa..6a703ded853 100644 --- a/Tests/BuildTests/BuildOperationTests.swift +++ b/Tests/BuildTests/BuildOperationTests.swift @@ -22,14 +22,16 @@ import class TSCBasic.InMemoryFileSystem final class BuildOperationTests: XCTestCase { func testDetectUnexpressedDependencies() throws { + let buildParameters = mockBuildParameters(shouldDisableLocalRpath: false) + let fs = InMemoryFileSystem(files: [ - "/path/to/build/debug/Lunch.build/Lunch.d" : "/Best.framework" + "\(buildParameters.dataPath)/debug/Lunch.build/Lunch.d" : "/Best.framework" ]) let observability = ObservabilitySystem.makeForTesting() let buildOp = BuildOperation( - productsBuildParameters: mockBuildParameters(shouldDisableLocalRpath: false), - toolsBuildParameters: mockBuildParameters(shouldDisableLocalRpath: false), + productsBuildParameters: buildParameters, + toolsBuildParameters: buildParameters, cacheBuildManifest: false, packageGraphLoader: { fatalError() }, additionalFileRules: [], diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index e69f605adb6..ea5452b4ab4 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -48,13 +48,13 @@ extension Build.BuildPlan { buildParameters: BuildParameters, graph: ModulesGraph, additionalFileRules: [FileRuleDescription] = [], - buildToolPluginInvocationResults: [ResolvedTarget.ID: [BuildToolPluginInvocationResult]] = [:], - prebuildCommandResults: [ResolvedTarget.ID: [PrebuildCommandResult]] = [:], + buildToolPluginInvocationResults: [ResolvedModule.ID: [BuildToolPluginInvocationResult]] = [:], + prebuildCommandResults: [ResolvedModule.ID: [PrebuildCommandResult]] = [:], fileSystem: any FileSystem, observabilityScope: ObservabilityScope ) throws { try self.init( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, additionalFileRules: additionalFileRules, @@ -927,7 +927,7 @@ final class BuildPlanTests: XCTestCase { buildPath: buildDirPath, config: .release, toolchain: UserToolchain.default, - targetTriple: UserToolchain.default.targetTriple, + triple: UserToolchain.default.targetTriple, useExplicitModuleBuild: true ), graph: graph, @@ -1157,11 +1157,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope )) - XCTAssertEqual(Set(result.productMap.keys), ["APackageTests"]) + XCTAssertEqual(Set(result.productMap.keys.map(\.productName)), ["APackageTests"]) #if os(macOS) - XCTAssertEqual(Set(result.targetMap.keys), ["ATarget", "BTarget", "ATargetTests"]) + XCTAssertEqual(Set(result.targetMap.keys.map(\.targetName)), ["ATarget", "BTarget", "ATargetTests"]) #else - XCTAssertEqual(Set(result.targetMap.keys), [ + XCTAssertEqual(Set(result.targetMap.keys.map(\.targetName)), [ "APackageTests", "APackageDiscoveredTests", "ATarget", @@ -1511,7 +1511,13 @@ final class BuildPlanTests: XCTestCase { ]) #endif - let buildProduct = try XCTUnwrap(result.productMap["exe"]) + let buildProduct = try XCTUnwrap( + result.productMap[.init( + productName: "exe", + packageIdentity: "Pkg", + buildTriple: .destination + )] + ) XCTAssertEqual(Array(buildProduct.objects), [ buildPath.appending(components: "exe.build", "main.c.o"), buildPath.appending(components: "extlib.build", "extlib.c.o"), @@ -1755,8 +1761,9 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters() let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1828,7 +1835,7 @@ final class BuildPlanTests: XCTestCase { "@\(buildPath.appending(components: "exe.product", "Objects.LinkFileList"))", "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift-5.5/macosx", "-target", defaultTargetTriple, - "-Xlinker", "-add_ast_path", "-Xlinker", "/path/to/build/debug/exe.build/exe.swiftmodule", + "-Xlinker", "-add_ast_path", "-Xlinker", "/path/to/build/\(buildParameters.triple)/debug/exe.build/exe.swiftmodule", "-g", ]) #elseif os(Windows) @@ -1884,8 +1891,9 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters() let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1895,8 +1903,8 @@ final class BuildPlanTests: XCTestCase { let lib = try result.target(for: "lib").clangTarget() XCTAssertEqual(try lib.objects, [ - AbsolutePath("/path/to/build/debug/lib.build/lib.S.o"), - AbsolutePath("/path/to/build/debug/lib.build/lib.c.o"), + AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/lib.build/lib.S.o"), + AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/lib.build/lib.c.o"), ]) } @@ -2614,7 +2622,7 @@ final class BuildPlanTests: XCTestCase { // Verify that `-lstdc++` is passed instead of `-lc++` when cross-compiling to Linux. result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .arm64Linux), + buildParameters: mockBuildParameters(triple: .arm64Linux), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -3425,7 +3433,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .windows), + buildParameters: mockBuildParameters(triple: .windows), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -3509,7 +3517,7 @@ final class BuildPlanTests: XCTestCase { try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( canRenameEntrypointFunctionName: true, - targetTriple: triple + triple: triple ), graph: graph, fileSystem: fs, @@ -3706,7 +3714,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .init("arm64-apple-ios")), + buildParameters: mockBuildParameters(triple: .init("arm64-apple-ios")), graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3783,7 +3791,7 @@ final class BuildPlanTests: XCTestCase { // constraints above are valid. XCTAssertNoThrow( _ = try BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .arm64iOS), + buildParameters: mockBuildParameters(triple: .arm64iOS), graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3793,7 +3801,7 @@ final class BuildPlanTests: XCTestCase { // For completeness, the invalid target should still throw an error. XCTAssertThrows(Diagnostics.fatalError) { _ = try BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .x86_64MacOS), + buildParameters: mockBuildParameters(triple: .x86_64MacOS), graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3856,7 +3864,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertThrows(Diagnostics.fatalError) { _ = try BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .x86_64MacOS), + buildParameters: mockBuildParameters(triple: .x86_64MacOS), graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -4022,7 +4030,7 @@ final class BuildPlanTests: XCTestCase { func createResult(for dest: Basics.Triple) throws -> BuildPlanResult { try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: dest), + buildParameters: mockBuildParameters(triple: dest), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4090,7 +4098,7 @@ final class BuildPlanTests: XCTestCase { do { let result = try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( - targetTriple: .x86_64Linux, + triple: .x86_64Linux, omitFramePointers: true ), graph: graph, @@ -4147,7 +4155,7 @@ final class BuildPlanTests: XCTestCase { do { let result = try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( - targetTriple: .x86_64Linux, + triple: .x86_64Linux, omitFramePointers: false ), graph: graph, @@ -4511,7 +4519,7 @@ final class BuildPlanTests: XCTestCase { swiftCompilerFlags: [cliFlag(tool: .swiftCompiler)], linkerFlags: [cliFlag(tool: .linker)] ), - targetTriple: targetTriple + triple: targetTriple ) let result = try BuildPlanResult(plan: BuildPlan( buildParameters: buildParameters, @@ -4796,8 +4804,9 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters() let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4813,7 +4822,7 @@ final class BuildPlanTests: XCTestCase { [ .anySequence, "-emit-objc-header", - "-emit-objc-header-path", "/path/to/build/debug/Foo.build/Foo-Swift.h", + "-emit-objc-header-path", "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4823,7 +4832,7 @@ final class BuildPlanTests: XCTestCase { [ .anySequence, "-emit-objc-header", - "-emit-objc-header-path", "/path/to/build/debug/Foo.build/Foo-Swift.h", + "-emit-objc-header-path", "/path/to/build/\(buildParameters.triple)/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4833,12 +4842,12 @@ final class BuildPlanTests: XCTestCase { #if os(macOS) XCTAssertMatch( barTarget, - [.anySequence, "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", .anySequence] + [.anySequence, "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] ) #else XCTAssertNoMatch( barTarget, - [.anySequence, "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", .anySequence] + [.anySequence, "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] ) #endif @@ -4896,8 +4905,9 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters() let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4914,7 +4924,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4925,7 +4935,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4937,7 +4947,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -4946,7 +4956,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5006,8 +5016,9 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters() let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5028,7 +5039,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -5039,7 +5050,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -5051,7 +5062,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5060,7 +5071,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5110,7 +5121,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .x86_64Linux), + buildParameters: mockBuildParameters(triple: .x86_64Linux), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5414,7 +5425,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let plan = try BuildPlan( - buildParameters: mockBuildParameters(targetTriple: .wasi), + buildParameters: mockBuildParameters(triple: .wasi), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5547,7 +5558,7 @@ final class BuildPlanTests: XCTestCase { let supportingTriples: [Basics.Triple] = [.x86_64Linux, .arm64Linux, .wasi] for triple in supportingTriples { let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, targetTriple: triple), + buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: triple), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5672,7 +5683,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: targetTriple), + buildParameters: mockBuildParameters(triple: targetTriple), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5801,7 +5812,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(targetTriple: targetTriple), + buildParameters: mockBuildParameters(triple: targetTriple), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -6074,7 +6085,13 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope )) - switch try XCTUnwrap(result.targetMap["ExtLib"]) { + switch try XCTUnwrap( + result.targetMap[.init( + targetName: "ExtLib", + packageIdentity: "ExtPkg", + buildTriple: .destination + )] + ) { case .swift(let swiftTarget): if #available(macOS 13, *) { // `.contains` is only available in macOS 13 or newer XCTAssertTrue(try swiftTarget.compileArguments().contains(["-user-module-version", "1.0.0"])) @@ -6232,7 +6249,13 @@ final class BuildPlanTests: XCTestCase { result.checkTargetsCount(3) XCTAssertTrue(result.targetMap.values.contains { $0.target.name == "FooLogging" }) XCTAssertTrue(result.targetMap.values.contains { $0.target.name == "BarLogging" }) - let buildProduct = try XCTUnwrap(result.productMap["exe"]) + let buildProduct = try XCTUnwrap( + result.productMap[.init( + productName: "exe", + packageIdentity: "thisPkg", + buildTriple: .destination + )] + ) let dylibs = Array(buildProduct.dylibs.map({$0.product.name})).sorted() XCTAssertEqual(dylibs, ["BarLogging", "FooLogging"]) } diff --git a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift index 7b8a01802d2..f8361e473df 100644 --- a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift +++ b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift @@ -25,6 +25,27 @@ final class ClangTargetBuildDescriptionTests: XCTestCase { XCTAssertFalse(try targetDescription.basicArguments().contains("-w")) } + func testSwiftCorelibsFoundationIncludeWorkaround() throws { + let toolchain = MockToolchain(swiftResourcesPath: AbsolutePath("/fake/path/lib/swift")) + + let macosParameters = mockBuildParameters(toolchain: toolchain, triple: .macOS) + let linuxParameters = mockBuildParameters(toolchain: toolchain, triple: .arm64Linux) + let androidParameters = mockBuildParameters(toolchain: toolchain, triple: .arm64Android) + + let macDescription = try makeTargetBuildDescription("swift-corelibs-foundation", + buildParameters: macosParameters) + XCTAssertFalse(try macDescription.basicArguments().contains("\(macosParameters.toolchain.swiftResourcesPath!)")) + + let linuxDescription = try makeTargetBuildDescription("swift-corelibs-foundation", + buildParameters: linuxParameters) + print(try linuxDescription.basicArguments()) + XCTAssertTrue(try linuxDescription.basicArguments().contains("\(linuxParameters.toolchain.swiftResourcesPath!)")) + + let androidDescription = try makeTargetBuildDescription("swift-corelibs-foundation", + buildParameters: androidParameters) + XCTAssertTrue(try androidDescription.basicArguments().contains("\(androidParameters.toolchain.swiftResourcesPath!)")) + } + func testWarningSuppressionForRemotePackages() throws { let targetDescription = try makeTargetBuildDescription("test-warning-supression", usesSourceControl: true) XCTAssertTrue(try targetDescription.basicArguments().contains("-w")) @@ -44,8 +65,8 @@ final class ClangTargetBuildDescriptionTests: XCTestCase { ) } - private func makeResolvedTarget() throws -> ResolvedTarget { - ResolvedTarget( + private func makeResolvedTarget() throws -> ResolvedModule { + ResolvedModule( packageIdentity: .plain("dummy"), underlying: try makeClangTarget(), dependencies: [], diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 504ba051f59..56d6bb9cabb 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -14,8 +14,10 @@ import struct Basics.AbsolutePath import class Basics.ObservabilitySystem import class Build.BuildPlan import class Build.ProductBuildDescription +import enum Build.TargetBuildDescription import class Build.SwiftTargetBuildDescription import struct Basics.Triple +import enum PackageGraph.BuildTriple import class PackageModel.Manifest import struct PackageModel.TargetDescription import func SPMTestSupport.loadPackageGraph @@ -25,7 +27,7 @@ import func SPMTestSupport.embeddedCxxInteropPackageGraph @_spi(SwiftPMInternal) import func SPMTestSupport.macrosPackageGraph - +import func SPMTestSupport.macrosTestsPackageGraph import func SPMTestSupport.mockBuildParameters @_spi(SwiftPMInternal) @@ -43,7 +45,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { var (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: "/Pkg") let triple = try Triple("wasm32-unknown-none-wasm") - var parameters = mockBuildParameters(targetTriple: triple) + var parameters = mockBuildParameters(triple: triple) parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true var result = try BuildPlanResult(plan: BuildPlan( buildParameters: parameters, @@ -106,7 +108,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: pkgPath) var parameters = mockBuildParameters( - config: .release, targetTriple: .wasi, linkerDeadStrip: true + config: .release, triple: .wasi, linkerDeadStrip: true ) parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true let result = try BuildPlanResult(plan: BuildPlan( @@ -138,7 +140,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: pkgPath) - var parameters = mockBuildParameters(targetTriple: .wasi) + var parameters = mockBuildParameters(triple: .wasi) parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true let result = try BuildPlanResult(plan: BuildPlan( buildParameters: parameters, @@ -153,7 +155,12 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let buildPath = result.plan.productsBuildPath - let lib = try result.target(for: "lib").clangTarget() + let lib = try XCTUnwrap( + result.allTargets(named: "lib") + .map { try $0.clangTarget() } + .first { $0.target.buildTriple == .destination } + ) + XCTAssertEqual(try lib.basicArguments(isCXX: false), [ "-target", "wasm32-unknown-wasi", "-O0", "-DSWIFT_PACKAGE=1", "-DDEBUG=1", @@ -212,4 +219,130 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let testPathExtension = try testBuildDescription.binaryPath.extension XCTAssertEqual(testPathExtension, "wasm") } + + func testMacros() throws { + let (graph, fs, scope) = try macrosPackageGraph() + + let destinationTriple = Triple.arm64Linux + let toolsTriple = Triple.x86_64MacOS + let plan = try BuildPlan( + destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), + toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + graph: graph, + fileSystem: fs, + observabilityScope: scope + ) + let result = try BuildPlanResult(plan: plan) + result.checkProductsCount(3) + result.checkTargetsCount(10) + + XCTAssertTrue(try result.allTargets(named: "SwiftSyntax") + .map { try $0.swiftTarget() } + .contains { $0.target.buildTriple == .tools }) + try result.check(buildTriple: .tools, triple: toolsTriple, for: "MMIOMacros") + try result.check(buildTriple: .destination, triple: destinationTriple, for: "MMIO") + try result.check(buildTriple: .destination, triple: destinationTriple, for: "Core") + try result.check(buildTriple: .destination, triple: destinationTriple, for: "HAL") + + let macroProducts = result.allProducts(named: "MMIOMacros") + XCTAssertEqual(macroProducts.count, 1) + let macroProduct = try XCTUnwrap(macroProducts.first) + XCTAssertEqual(macroProduct.buildParameters.triple, toolsTriple) + + let mmioTargets = try result.allTargets(named: "MMIO").map { try $0.swiftTarget() } + XCTAssertEqual(mmioTargets.count, 1) + let mmioTarget = try XCTUnwrap(mmioTargets.first) + let compileArguments = try mmioTarget.emitCommandLine() + XCTAssertMatch( + compileArguments, + [ + "-I", .equal(mmioTarget.moduleOutputPath.parentDirectory.pathString), + .anySequence, + "-Xfrontend", "-load-plugin-executable", + // Verify that macros are located in the tools triple directory. + "-Xfrontend", .contains(toolsTriple.tripleString) + ] + ) + } + + func testMacrosTests() throws { + let (graph, fs, scope) = try macrosTestsPackageGraph() + + let destinationTriple = Triple.arm64Linux + let toolsTriple = Triple.x86_64MacOS + let plan = try BuildPlan( + destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), + toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + graph: graph, + fileSystem: fs, + observabilityScope: scope + ) + let result = try BuildPlanResult(plan: plan) + result.checkProductsCount(2) + result.checkTargetsCount(15) + + XCTAssertTrue(try result.allTargets(named: "SwiftSyntax") + .map { try $0.swiftTarget() } + .contains { $0.target.buildTriple == .tools }) + + try result.check(buildTriple: .tools, triple: toolsTriple, for: "swift-mmioPackageTests") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "swift-mmioPackageDiscoveredTests") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "MMIOMacros") + try result.check(buildTriple: .destination, triple: destinationTriple, for: "MMIO") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "MMIOMacrosTests") + + let macroProducts = result.allProducts(named: "MMIOMacros") + XCTAssertEqual(macroProducts.count, 1) + let macroProduct = try XCTUnwrap(macroProducts.first) + XCTAssertEqual(macroProduct.buildParameters.triple, toolsTriple) + + let mmioTargets = try result.allTargets(named: "MMIO").map { try $0.swiftTarget() } + XCTAssertEqual(mmioTargets.count, 1) + let mmioTarget = try XCTUnwrap(mmioTargets.first) + let compileArguments = try mmioTarget.emitCommandLine() + XCTAssertMatch( + compileArguments, + [ + "-I", .equal(mmioTarget.moduleOutputPath.parentDirectory.pathString), + .anySequence, + "-Xfrontend", "-load-plugin-executable", + // Verify that macros are located in the tools triple directory. + "-Xfrontend", .contains(toolsTriple.tripleString) + ] + ) + } +} + +extension BuildPlanResult { + func allTargets(named name: String) throws -> some Collection { + self.targetMap + .filter { $0.0.targetName == name } + .values + } + + func allProducts(named name: String) -> some Collection { + self.productMap + .filter { $0.0.productName == name } + .values + } + + func check( + buildTriple: BuildTriple, + triple: Triple, + for target: String, + file: StaticString = #file, + line: UInt = #line + ) throws { + let targets = self.targetMap.filter { + $0.key.targetName == target && $0.key.buildTriple == buildTriple + } + XCTAssertEqual(targets.count, 1, file: file, line: line) + + let target = try XCTUnwrap( + targets.first?.value, + file: file, + line: line + ).swiftTarget() + XCTAssertMatch(try target.emitCommandLine(), [.contains(triple.tripleString)], file: file, line: line) + } } diff --git a/Tests/BuildTests/LLBuildManifestBuilderTests.swift b/Tests/BuildTests/LLBuildManifestBuilderTests.swift index f66e0dc5e25..b298e6e43a6 100644 --- a/Tests/BuildTests/LLBuildManifestBuilderTests.swift +++ b/Tests/BuildTests/LLBuildManifestBuilderTests.swift @@ -53,7 +53,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .release )) var plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -70,8 +70,8 @@ final class LLBuildManifestBuilderTests: XCTestCase { ) try llbuild.createProductCommand(buildProduct) - let basicReleaseCommandNames = [ - AbsolutePath("/path/to/build/release/exe.product/Objects.LinkFileList").pathString, + var basicReleaseCommandNames = [ + AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, "", "C.exe-release.exe", ] @@ -88,7 +88,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .debug )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -98,12 +98,12 @@ final class LLBuildManifestBuilderTests: XCTestCase { result = try BuildPlanResult(plan: plan) buildProduct = try result.buildProduct(for: "exe") - llbuild = LLBuildManifestBuilder(plan, fileSystem: localFileSystem, observabilityScope: observability.topScope) + llbuild = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: observability.topScope) try llbuild.createProductCommand(buildProduct) let entitlementsCommandName = "C.exe-debug.exe-entitlements" - let basicDebugCommandNames = [ - AbsolutePath("/path/to/build/debug/exe.product/Objects.LinkFileList").pathString, + var basicDebugCommandNames = [ + AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, "", "C.exe-debug.exe", ] @@ -111,7 +111,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { XCTAssertEqual( llbuild.manifest.commands.map(\.key).sorted(), (basicDebugCommandNames + [ - AbsolutePath("/path/to/build/debug/exe-entitlement.plist").pathString, + AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe-entitlement.plist").pathString, entitlementsCommandName, ]).sorted() ) @@ -124,8 +124,8 @@ final class LLBuildManifestBuilderTests: XCTestCase { XCTAssertEqual( entitlementsCommand.inputs, [ - .file("/path/to/build/debug/exe", isMutated: true), - .file("/path/to/build/debug/exe-entitlement.plist"), + .file("/path/to/build/\(buildParameters.triple)/debug/exe", isMutated: true), + .file("/path/to/build/\(buildParameters.triple)/debug/exe-entitlement.plist"), ] ) XCTAssertEqual( @@ -142,7 +142,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .release )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -155,6 +155,12 @@ final class LLBuildManifestBuilderTests: XCTestCase { llbuild = LLBuildManifestBuilder(plan, fileSystem: localFileSystem, observabilityScope: observability.topScope) try llbuild.createProductCommand(buildProduct) + basicReleaseCommandNames = [ + AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-release.exe", + ] + XCTAssertEqual( llbuild.manifest.commands.map(\.key).sorted(), basicReleaseCommandNames.sorted() @@ -167,7 +173,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .debug )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -177,12 +183,38 @@ final class LLBuildManifestBuilderTests: XCTestCase { result = try BuildPlanResult(plan: plan) buildProduct = try result.buildProduct(for: "exe") - llbuild = LLBuildManifestBuilder(plan, fileSystem: localFileSystem, observabilityScope: observability.topScope) + llbuild = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: observability.topScope) try llbuild.createProductCommand(buildProduct) + basicDebugCommandNames = [ + AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-debug.exe", + ] + XCTAssertEqual( llbuild.manifest.commands.map(\.key).sorted(), basicDebugCommandNames.sorted() ) } + + /// Verifies that two targets with the same name but different triples don't share same build manifest keys. + func testToolsBuildTriple() throws { + let (graph, fs, scope) = try macrosPackageGraph() + let productsTriple = Triple.x86_64MacOS + let toolsTriple = Triple.arm64Linux + + let plan = try BuildPlan( + destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: productsTriple), + toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + graph: graph, + fileSystem: fs, + observabilityScope: scope + ) + + let builder = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: scope) + let manifest = try builder.generateManifest(at: "/manifest") + + XCTAssertNotNil(manifest.commands["C.SwiftSyntax-debug-tool.module"]) + } } diff --git a/Tests/BuildTests/ModuleAliasingBuildTests.swift b/Tests/BuildTests/ModuleAliasingBuildTests.swift index 52c15c327c7..73b5ed2b7fb 100644 --- a/Tests/BuildTests/ModuleAliasingBuildTests.swift +++ b/Tests/BuildTests/ModuleAliasingBuildTests.swift @@ -694,8 +694,9 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -724,33 +725,33 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertMatch( fooLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] ) XCTAssertMatch( barLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] ) XCTAssertMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #else XCTAssertNoMatch( fooLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( barLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #endif } @@ -812,8 +813,9 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + buildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -842,23 +844,23 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertMatch( otherLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] ) XCTAssertMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #else XCTAssertNoMatch( otherLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #endif } diff --git a/Tests/BuildTests/PluginsBuildPlanTests.swift b/Tests/BuildTests/PluginsBuildPlanTests.swift index 892c3da6725..7b2a1a78378 100644 --- a/Tests/BuildTests/PluginsBuildPlanTests.swift +++ b/Tests/BuildTests/PluginsBuildPlanTests.swift @@ -48,8 +48,16 @@ final class PluginsBuildPlanTests: XCTestCase { let (stdout, stderr) = try executeSwiftPackage(fixturePath, extraArgs: ["-v", "build-plugin-dependency"]) XCTAssertMatch(stdout, .contains("Hello from dependencies-stub")) XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!")) - XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool")))) - XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/placeholder")))) + XCTAssertTrue( + localFileSystem.exists( + fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool-tool")) + ) + ) + XCTAssertTrue( + localFileSystem.exists( + fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/placeholder")) + ) + ) } // When cross compiling the final product, plugin dependencies should still be built for the host @@ -57,8 +65,16 @@ final class PluginsBuildPlanTests: XCTestCase { let (stdout, stderr) = try executeSwiftPackage(fixturePath, extraArgs: ["--triple", targetTriple, "-v", "build-plugin-dependency"]) XCTAssertMatch(stdout, .contains("Hello from dependencies-stub")) XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!")) - XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool")))) - XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/\(targetTriple)/debug/placeholder")))) + XCTAssertTrue( + localFileSystem.exists( + fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool-tool")) + ) + ) + XCTAssertTrue( + localFileSystem.exists( + fixturePath.appending(RelativePath(".build/\(targetTriple)/debug/placeholder")) + ) + ) } } } diff --git a/Tests/BuildTests/ProductBuildDescriptionTests.swift b/Tests/BuildTests/ProductBuildDescriptionTests.swift index f07646f64a5..444565cef7b 100644 --- a/Tests/BuildTests/ProductBuildDescriptionTests.swift +++ b/Tests/BuildTests/ProductBuildDescriptionTests.swift @@ -53,7 +53,7 @@ final class ProductBuildDescriptionTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let id = ResolvedProduct.ID(targetName: "exe", packageIdentity: .plain("pkg"), buildTriple: .destination) + let id = ResolvedProduct.ID(productName: "exe", packageIdentity: .plain("pkg"), buildTriple: .destination) let package = try XCTUnwrap(graph.rootPackages.first) let product = try XCTUnwrap(graph.allProducts[id]) diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 83d53e15b28..1b38f1ea6eb 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -1840,9 +1840,15 @@ final class PackageCommandTests: CommandsTestCase { """ ) let hostTriple = try UserToolchain(swiftSDK: .hostSwiftSDK()).targetTriple - let hostTripleString = hostTriple.isDarwin() ? hostTriple.tripleString(forPlatformVersion: "") : hostTriple.tripleString - try localFileSystem.writeFileContents(packageDir.appending(components: "Binaries", "LocalBinaryTool.artifactbundle", "info.json"), string: - """ + let hostTripleString = if hostTriple.isDarwin() { + hostTriple.tripleString(forPlatformVersion: "") + } else { + hostTriple.tripleString + } + + try localFileSystem.writeFileContents( + packageDir.appending(components: "Binaries", "LocalBinaryTool.artifactbundle", "info.json"), + string: """ { "schemaVersion": "1.0", "artifacts": { "LocalBinaryTool": { @@ -1858,11 +1864,13 @@ final class PackageCommandTests: CommandsTestCase { } """ ) - try localFileSystem.writeFileContents(packageDir.appending(components: "Sources", "LocalBuiltTool", "main.swift"), string: - #"print("Hello")"# + try localFileSystem.writeFileContents( + packageDir.appending(components: "Sources", "LocalBuiltTool", "main.swift"), + string: #"print("Hello")"# ) - try localFileSystem.writeFileContents(packageDir.appending(components: "Plugins", "MyPlugin", "plugin.swift"), string: - """ + try localFileSystem.writeFileContents( + packageDir.appending(components: "Plugins", "MyPlugin", "plugin.swift"), + string: """ import PackagePlugin import Foundation @main @@ -1923,8 +1931,9 @@ final class PackageCommandTests: CommandsTestCase { ) // Create the sample vendored dependency package. - try localFileSystem.writeFileContents(packageDir.appending(components: "VendoredDependencies", "HelperPackage", "Package.swift"), string: - """ + try localFileSystem.writeFileContents( + packageDir.appending(components: "VendoredDependencies", "HelperPackage", "Package.swift"), + string: """ // swift-tools-version: 5.5 import PackageDescription let package = Package( @@ -1950,9 +1959,25 @@ final class PackageCommandTests: CommandsTestCase { ) """ ) - try localFileSystem.writeFileContents(packageDir.appending(components: "VendoredDependencies", "HelperPackage", "Sources", "HelperLibrary", "library.swift"), string: "public func Bar() { }" + try localFileSystem.writeFileContents( + packageDir.appending( + components: "VendoredDependencies", + "HelperPackage", + "Sources", + "HelperLibrary", + "library.swift" + ), + string: "public func Bar() { }" ) - try localFileSystem.writeFileContents(packageDir.appending(components: "VendoredDependencies", "HelperPackage", "Sources", "RemoteBuiltTool", "main.swift"), string: #"print("Hello")"# + try localFileSystem.writeFileContents( + packageDir.appending( + components: "VendoredDependencies", + "HelperPackage", + "Sources", + "RemoteBuiltTool", + "main.swift" + ), + string: #"print("Hello")"# ) // Check that we can invoke the plugin with the "plugin" subcommand. diff --git a/Tests/CommandsTests/SwiftCommandStateTests.swift b/Tests/CommandsTests/SwiftCommandStateTests.swift index cbd580fa1fc..e7204aad341 100644 --- a/Tests/CommandsTests/SwiftCommandStateTests.swift +++ b/Tests/CommandsTests/SwiftCommandStateTests.swift @@ -255,7 +255,7 @@ final class SwiftCommandStateTests: CommandsTestCase { let explicitDwarfOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc", "-debug-info-format", "dwarf"]) let explicitDwarf = try SwiftCommandState.makeMockState(options: explicitDwarfOptions) plan = try BuildPlan( - productsBuildParameters: explicitDwarf.productsBuildParameters, + destinationBuildParameters: explicitDwarf.productsBuildParameters, toolsBuildParameters: explicitDwarf.toolsBuildParameters, graph: graph, fileSystem: fs, @@ -270,7 +270,7 @@ final class SwiftCommandStateTests: CommandsTestCase { let explicitCodeView = try SwiftCommandState.makeMockState(options: explicitCodeViewOptions) plan = try BuildPlan( - productsBuildParameters: explicitCodeView.productsBuildParameters, + destinationBuildParameters: explicitCodeView.productsBuildParameters, toolsBuildParameters: explicitCodeView.productsBuildParameters, graph: graph, fileSystem: fs, @@ -293,7 +293,7 @@ final class SwiftCommandStateTests: CommandsTestCase { let implicitDwarfOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc"]) let implicitDwarf = try SwiftCommandState.makeMockState(options: implicitDwarfOptions) plan = try BuildPlan( - productsBuildParameters: implicitDwarf.productsBuildParameters, + destinationBuildParameters: implicitDwarf.productsBuildParameters, toolsBuildParameters: implicitDwarf.toolsBuildParameters, graph: graph, fileSystem: fs, @@ -306,7 +306,7 @@ final class SwiftCommandStateTests: CommandsTestCase { let explicitNoDebugInfoOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc", "-debug-info-format", "none"]) let explicitNoDebugInfo = try SwiftCommandState.makeMockState(options: explicitNoDebugInfoOptions) plan = try BuildPlan( - productsBuildParameters: explicitNoDebugInfo.productsBuildParameters, + destinationBuildParameters: explicitNoDebugInfo.productsBuildParameters, toolsBuildParameters: explicitNoDebugInfo.toolsBuildParameters, graph: graph, fileSystem: fs, diff --git a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift index c688b1d5439..6073cc22896 100644 --- a/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift +++ b/Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift @@ -164,9 +164,9 @@ final class PackageGraphPerfTests: XCTestCasePerf { } func testRecursiveDependencies() throws { - var resolvedTarget = ResolvedTarget.mock(packageIdentity: "pkg", name: "t0") + var resolvedTarget = ResolvedModule.mock(packageIdentity: "pkg", name: "t0") for i in 1..<1000 { - resolvedTarget = ResolvedTarget.mock(packageIdentity: "pkg", name: "t\(i)", deps: resolvedTarget) + resolvedTarget = ResolvedModule.mock(packageIdentity: "pkg", name: "t\(i)", deps: resolvedTarget) } let N = 10 diff --git a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift new file mode 100644 index 00000000000..dc50bab88c7 --- /dev/null +++ b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@testable +import SPMTestSupport + +@testable +import PackageGraph + +import XCTest + +final class CrossCompilationPackageGraphTests: XCTestCase { + func testTrivialPackage() throws { + let graph = try trivialPackageGraph(pkgRootPath: "/Pkg").graph + try PackageGraphTester(graph) { result in + result.check(packages: "Pkg") + // "SwiftSyntax" is included for both host and target triples and is not pruned on this level + result.check(targets: "app", "lib") + result.check(testModules: "test") + result.checkTarget("app") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "lib") + } + try result.checkTargets("lib") { results in + let result = try XCTUnwrap(results.first { $0.target.buildTriple == .destination }) + result.check(dependencies: []) + } + result.checkTarget("test") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "lib") + } + } + } + + func testMacros() throws { + let graph = try macrosPackageGraph().graph + try PackageGraphTester(graph) { result in + result.check(packages: "swift-firmware", "swift-mmio", "swift-syntax") + // "SwiftSyntax" is included for both host and target triples and is not pruned on this level + result.check( + targets: "Core", + "HAL", + "MMIO", + "MMIOMacros", + "SwiftSyntax", + "SwiftSyntax" + ) + result.check(testModules: "CoreTests", "HALTests") + try result.checkTargets("Core") { results in + let result = try XCTUnwrap(results.first { $0.target.buildTriple == .destination }) + result.check(dependencies: "HAL") + } + try result.checkTargets("HAL") { results in + let result = try XCTUnwrap(results.first { $0.target.buildTriple == .destination }) + result.check(buildTriple: .destination) + result.check(dependencies: "MMIO") + } + try result.checkTargets("MMIO") { results in + let result = try XCTUnwrap(results.first { $0.target.buildTriple == .destination }) + result.check(buildTriple: .destination) + result.check(dependencies: "MMIOMacros") + } + try result.checkTargets("MMIOMacros") { results in + let result = try XCTUnwrap(results.first(where: { $0.target.buildTriple == .tools })) + result.check(buildTriple: .tools) + result.checkDependency("SwiftSyntax") { result in + result.checkProduct { result in + result.check(buildTriple: .tools) + result.checkTarget("SwiftSyntax") { result in + result.check(buildTriple: .tools) + } + } + } + } + + result.checkTargets("SwiftSyntax") { results in + XCTAssertEqual(results.count, 2) + + XCTAssertEqual(results.filter({ $0.target.buildTriple == .tools }).count, 1) + XCTAssertEqual(results.filter({ $0.target.buildTriple == .destination }).count, 1) + } + } + } + + func testMacrosTests() throws { + let graph = try macrosTestsPackageGraph().graph + PackageGraphTester(graph) { result in + result.check(packages: "swift-mmio", "swift-syntax") + // "SwiftSyntax" is included for both host and target triples and is not pruned on this level + result.check( + targets: "MMIO", + "MMIOMacros", + "SwiftCompilerPlugin", + "SwiftCompilerPlugin", + "SwiftCompilerPluginMessageHandling", + "SwiftCompilerPluginMessageHandling", + "SwiftSyntax", + "SwiftSyntax", + "SwiftSyntaxMacros", + "SwiftSyntaxMacros", + "SwiftSyntaxMacrosTestSupport", + "SwiftSyntaxMacrosTestSupport" + ) + result.check(testModules: "MMIOMacrosTests") + result.checkTarget("MMIO") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "MMIOMacros") + } + result.checkTargets("MMIOMacros") { results in + XCTAssertEqual(results.count, 1) + } + result.checkTarget("MMIOMacrosTests") { result in + result.check(buildTriple: .tools) + result.checkDependency("MMIOMacros") { result in + result.checkTarget { result in + result.check(buildTriple: .tools) + result.checkDependency("SwiftSyntaxMacros") { result in + result.checkProduct { result in + result.check(buildTriple: .tools) + } + } + result.checkDependency("SwiftCompilerPlugin") { result in + result.checkProduct { result in + result.check(buildTriple: .tools) + result.checkTarget("SwiftCompilerPlugin") { result in + result.check(buildTriple: .tools) + result.checkDependency("SwiftCompilerPluginMessageHandling") { result in + result.checkTarget { result in + result.check(buildTriple: .tools) + } + } + } + } + } + } + } + } + + result.checkTargets("SwiftSyntax") { results in + XCTAssertEqual(results.count, 2) + + XCTAssertEqual(results.filter({ $0.target.buildTriple == .tools }).count, 1) + XCTAssertEqual(results.filter({ $0.target.buildTriple == .destination }).count, 1) + } + } + } +} diff --git a/Tests/PackageGraphTests/ResolvedTargetTests.swift b/Tests/PackageGraphTests/ResolvedTargetTests.swift index 5c10466603e..5546a9cc267 100644 --- a/Tests/PackageGraphTests/ResolvedTargetTests.swift +++ b/Tests/PackageGraphTests/ResolvedTargetTests.swift @@ -17,29 +17,29 @@ import PackageGraph import SPMTestSupport private func XCTAssertEqualTargetIDs( - _ lhs: [ResolvedTarget], - _ rhs: [ResolvedTarget], + _ lhs: [ResolvedModule], + _ rhs: [ResolvedModule], file: StaticString = #filePath, line: UInt = #line ) { XCTAssertEqual(lhs.map(\.id), rhs.map(\.id), file: file, line: line) } -final class ResolvedTargetDependencyTests: XCTestCase { +final class ResolvedModuleDependencyTests: XCTestCase { func test1() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2) + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2) XCTAssertEqualTargetIDs(try t3.recursiveTargetDependencies(), [t2, t1]) XCTAssertEqualTargetIDs(try t2.recursiveTargetDependencies(), [t1]) } func test2() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2, t1) - let t4 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t4", deps: t2, t3, t1) + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2, t1) + let t4 = ResolvedModule.mock(packageIdentity: "pkg", name: "t4", deps: t2, t3, t1) XCTAssertEqualTargetIDs(try t4.recursiveTargetDependencies(), [t3, t2, t1]) XCTAssertEqualTargetIDs(try t3.recursiveTargetDependencies(), [t2, t1]) @@ -47,10 +47,10 @@ final class ResolvedTargetDependencyTests: XCTestCase { } func test3() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2, t1) - let t4 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t4", deps: t1, t2, t3) + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2, t1) + let t4 = ResolvedModule.mock(packageIdentity: "pkg", name: "t4", deps: t1, t2, t3) XCTAssertEqualTargetIDs(try t4.recursiveTargetDependencies(), [t3, t2, t1]) XCTAssertEqualTargetIDs(try t3.recursiveTargetDependencies(), [t2, t1]) @@ -58,10 +58,10 @@ final class ResolvedTargetDependencyTests: XCTestCase { } func test4() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2) - let t4 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t4", deps: t3) + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2) + let t4 = ResolvedModule.mock(packageIdentity: "pkg", name: "t4", deps: t3) XCTAssertEqualTargetIDs(try t4.recursiveTargetDependencies(), [t3, t2, t1]) XCTAssertEqualTargetIDs(try t3.recursiveTargetDependencies(), [t2, t1]) @@ -69,12 +69,12 @@ final class ResolvedTargetDependencyTests: XCTestCase { } func test5() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2) - let t4 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t4", deps: t3) - let t5 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t5", deps: t2) - let t6 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t6", deps: t5, t4) + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2) + let t4 = ResolvedModule.mock(packageIdentity: "pkg", name: "t4", deps: t3) + let t5 = ResolvedModule.mock(packageIdentity: "pkg", name: "t5", deps: t2) + let t6 = ResolvedModule.mock(packageIdentity: "pkg", name: "t6", deps: t5, t4) // precise order is not important, but it is important that the following are true let t6rd = try t6.recursiveTargetDependencies().map(\.id) @@ -91,12 +91,12 @@ final class ResolvedTargetDependencyTests: XCTestCase { } func test6() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t3 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t3", deps: t2) - let t4 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t4", deps: t3) - let t5 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t5", deps: t2) - let t6 = ResolvedTarget.mock( + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t3 = ResolvedModule.mock(packageIdentity: "pkg", name: "t3", deps: t2) + let t4 = ResolvedModule.mock(packageIdentity: "pkg", name: "t4", deps: t3) + let t5 = ResolvedModule.mock(packageIdentity: "pkg", name: "t5", deps: t2) + let t6 = ResolvedModule.mock( packageIdentity: "pkg", name: "t6", deps: t4, @@ -118,10 +118,10 @@ final class ResolvedTargetDependencyTests: XCTestCase { } func testConditions() throws { - let t1 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t1") - let t2 = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t2NoConditions = ResolvedTarget.mock(packageIdentity: "pkg", name: "t2", deps: t1) - let t2WithConditions = ResolvedTarget.mock( + let t1 = ResolvedModule.mock(packageIdentity: "pkg", name: "t1") + let t2 = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t2NoConditions = ResolvedModule.mock(packageIdentity: "pkg", name: "t2", deps: t1) + let t2WithConditions = ResolvedModule.mock( packageIdentity: "pkg", name: "t2", deps: t1, diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index ab2b46e8785..0d21bf053c3 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -37,7 +37,7 @@ final class PluginInvocationTests: XCTestCase { "/Foo/Sources/Foo/SomeFile.abc" ) let observability = ObservabilitySystem.makeForTesting() - let graph = try loadPackageGraph( + let graph = try loadModulesGraph( fileSystem: fileSystem, manifests: [ Manifest.createRootManifest( @@ -77,7 +77,8 @@ final class PluginInvocationTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) PackageGraphTester(graph) { graph in graph.check(packages: "Foo") - graph.check(targets: "Foo", "FooPlugin", "FooTool") + // "FooTool" duplicated as it's present for both build tools and end products triples. + graph.check(targets: "Foo", "FooPlugin", "FooTool", "FooTool") graph.checkTarget("Foo") { target in target.check(dependencies: "FooPlugin") } @@ -85,8 +86,10 @@ final class PluginInvocationTests: XCTestCase { target.check(type: .plugin) target.check(dependencies: "FooTool") } - graph.checkTarget("FooTool") { target in - target.check(type: .executable) + graph.checkTargets("FooTool") { targets in + for target in targets { + target.check(type: .executable) + } } } @@ -191,13 +194,13 @@ final class PluginInvocationTests: XCTestCase { // Construct a canned input and run plugins using our MockPluginScriptRunner(). let outputDir = AbsolutePath("/Foo/.build") - let builtToolsDir = AbsolutePath("/path/to/build/debug") let pluginRunner = MockPluginScriptRunner() + let buildParameters = mockBuildParameters( + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) let results = try graph.invokeBuildToolPlugins( outputDir: outputDir, - buildParameters: mockBuildParameters( - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ), + buildParameters: buildParameters, additionalFileRules: [], toolSearchDirectories: [UserToolchain.default.swiftCompilerPath.parentDirectory], pkgConfigDirectories: [], @@ -205,11 +208,12 @@ final class PluginInvocationTests: XCTestCase { observabilityScope: observability.topScope, fileSystem: fileSystem ) + let builtToolsDir = AbsolutePath("/path/to/build/\(buildParameters.triple)/debug") // Check the canned output to make sure nothing was lost in transport. XCTAssertNoDiagnostics(observability.diagnostics) XCTAssertEqual(results.count, 1) - let (evalTargetID, (evalTarget, evalResults)) = try XCTUnwrap(results.first) + let (_, (evalTarget, evalResults)) = try XCTUnwrap(results.first) XCTAssertEqual(evalTarget.name, "Foo") XCTAssertEqual(evalResults.count, 1) @@ -1084,7 +1088,6 @@ final class PluginInvocationTests: XCTestCase { } } - XCTAssertEqual(count, 2) } } @@ -1092,7 +1095,7 @@ final class PluginInvocationTests: XCTestCase { func checkParseArtifactsPlatformCompatibility( artifactSupportedTriples: [Triple], hostTriple: Triple - ) async throws -> [ResolvedTarget.ID: [BuildToolPluginInvocationResult]] { + ) async throws -> [ResolvedModule.ID: [BuildToolPluginInvocationResult]] { // Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require). try XCTSkipIf(!UserToolchain.default.supportsSwiftConcurrency(), "skipping because test environment doesn't support concurrency") diff --git a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift index 29691c493d9..99c43463bf3 100644 --- a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift +++ b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift @@ -27,7 +27,7 @@ class SourceKitLSPAPITests: XCTestCase { ) let observability = ObservabilitySystem.makeForTesting() - let graph = try loadPackageGraph( + let graph = try loadModulesGraph( fileSystem: fs, manifests: [ Manifest.createRootManifest( @@ -42,17 +42,38 @@ class SourceKitLSPAPITests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) + let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) let plan = try BuildPlan( - productsBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), - toolsBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + destinationBuildParameters: buildParameters, + toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, observabilityScope: observability.topScope ) let description = BuildDescription(buildPlan: plan) - try description.checkArguments(for: "exe", graph: graph, partialArguments: ["-module-name", "exe", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/exe.build/exe.swiftmodule"], isPartOfRootPackage: true) - try description.checkArguments(for: "lib", graph: graph, partialArguments: ["-module-name", "lib", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/Modules/lib.swiftmodule"], isPartOfRootPackage: true) + try description.checkArguments( + for: "exe", + graph: graph, + partialArguments: [ + "-module-name", "exe", + "-emit-dependencies", + "-emit-module", + "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/exe.build/exe.swiftmodule" + ], + isPartOfRootPackage: true + ) + try description.checkArguments( + for: "lib", + graph: graph, + partialArguments: [ + "-module-name", "lib", + "-emit-dependencies", + "-emit-module", + "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/Modules/lib.swiftmodule" + ], + isPartOfRootPackage: true + ) } } From 59f1edd1456d4e6758a6ccf14b16c76d0040dcd5 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 25 Apr 2024 00:22:47 +0100 Subject: [PATCH 02/14] Include host triple test modules in `ResolvedPackage` (#7493) Modified `ResolvedModule` build triples were not reflected in `ResolvedPackage`, which excluded those modules from the build graph. Verified manually with `swift-foundation` and `swift-testing` packages. More comprehensive automated tests will be included in a future PR. Resolves https://github.com/apple/swift-package-manager/issues/7479. (cherry picked from commit b9eb3c138ec681d8858de4d8bf7d179758490ba1) # Conflicts: # Sources/PackageGraph/ModulesGraph+Loading.swift # Sources/PackageGraph/Resolution/ResolvedPackage.swift --- Sources/Basics/Errors.swift | 3 +-- .../BuildDescription/SwiftTargetBuildDescription.swift | 5 +++-- .../LLBuildManifestBuilder+Resources.swift | 2 +- .../Build/BuildManifest/LLBuildManifestBuilder.swift | 4 ++-- Sources/Build/BuildPlan/BuildPlan.swift | 2 +- Sources/PackageGraph/ModulesGraph+Loading.swift | 10 +++++++--- Sources/PackageGraph/Resolution/ResolvedPackage.swift | 4 ++-- .../BuildTests/ClangTargetBuildDescriptionTests.swift | 2 +- Tests/CommandsTests/PackageCommandTests.swift | 8 ++++---- 9 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Sources/Basics/Errors.swift b/Sources/Basics/Errors.swift index c0900f565d7..f075978da86 100644 --- a/Sources/Basics/Errors.swift +++ b/Sources/Basics/Errors.swift @@ -21,8 +21,7 @@ public struct InternalError: Error { private let description: String public init(_ description: String) { assertionFailure(description) - self - .description = + self.description = "Internal error. Please file a bug at https://github.com/apple/swift-package-manager/issues with this info. \(description)" } } diff --git a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift index 11120f45c62..eed9a9ce012 100644 --- a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift @@ -66,9 +66,10 @@ public final class SwiftTargetBuildDescription { /// Path to the bundle generated for this module (if any). var bundlePath: AbsolutePath? { if let bundleName = target.underlying.potentialBundleName, needsResourceBundle { - return self.defaultBuildParameters.bundlePath(named: bundleName) + let suffix = self.defaultBuildParameters.suffix(triple: self.target.buildTriple) + return self.defaultBuildParameters.bundlePath(named: bundleName + suffix) } else { - return .none + return nil } } diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift index 599c7c435d5..df561d46b8b 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift @@ -45,7 +45,7 @@ extension LLBuildManifestBuilder { outputs.append(output) } - let cmdName = target.target.getLLBuildResourcesCmdName(config: target.buildParameters.buildConfig) + let cmdName = target.target.getLLBuildResourcesCmdName(buildParameters: target.buildParameters) self.manifest.addPhonyCmd(name: cmdName, inputs: outputs, outputs: [.virtual(cmdName)]) return .virtual(cmdName) diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift index f4439ec7af9..87f998312bf 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -325,8 +325,8 @@ extension ResolvedModule { "\(self.name)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module" } - package func getLLBuildResourcesCmdName(config: String) -> String { - "\(self.name)-\(config).module-resources" + package func getLLBuildResourcesCmdName(buildParameters: BuildParameters) -> String { + "\(self.name)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module-resources" } } diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index f24d123e918..4da76802288 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -700,7 +700,7 @@ extension Basics.Diagnostic { extension BuildParameters { /// Returns a named bundle's path inside the build directory. func bundlePath(named name: String) -> AbsolutePath { - buildPath.appending(component: name + self.triple.nsbundleExtension) + self.buildPath.appending(component: name + self.triple.nsbundleExtension) } } diff --git a/Sources/PackageGraph/ModulesGraph+Loading.swift b/Sources/PackageGraph/ModulesGraph+Loading.swift index 4b0dbb57a3b..c3df08e343a 100644 --- a/Sources/PackageGraph/ModulesGraph+Loading.swift +++ b/Sources/PackageGraph/ModulesGraph+Loading.swift @@ -1097,13 +1097,17 @@ private final class ResolvedPackageBuilder: ResolvedBuilder { } override func constructImpl() throws -> ResolvedPackage { - return ResolvedPackage( + let products = try self.products.map { try $0.construct() } + var targets = products.reduce(into: IdentifiableSet()) { $0.formUnion($1.targets) } + try targets.formUnion(self.targets.map { try $0.construct() }) + + return try ResolvedPackage( underlying: self.package, defaultLocalization: self.defaultLocalization, supportedPlatforms: self.supportedPlatforms, dependencies: self.dependencies.map { $0.package.identity }, - targets: try self.targets.map{ try $0.construct() }, - products: try self.products.map{ try $0.construct() }, + targets: targets, + products: products, registryMetadata: self.registryMetadata, platformVersionProvider: self.platformVersionProvider ) diff --git a/Sources/PackageGraph/Resolution/ResolvedPackage.swift b/Sources/PackageGraph/Resolution/ResolvedPackage.swift index ef1d112573b..32536f0dbb1 100644 --- a/Sources/PackageGraph/Resolution/ResolvedPackage.swift +++ b/Sources/PackageGraph/Resolution/ResolvedPackage.swift @@ -34,7 +34,7 @@ public struct ResolvedPackage { public let underlying: Package /// The targets contained in the package. - public let targets: [ResolvedModule] + public let targets: IdentifiableSet /// The products produced by the package. public let products: [ResolvedProduct] @@ -58,7 +58,7 @@ public struct ResolvedPackage { defaultLocalization: String?, supportedPlatforms: [SupportedPlatform], dependencies: [PackageIdentity], - targets: [ResolvedModule], + targets: IdentifiableSet, products: [ResolvedProduct], registryMetadata: RegistryReleaseMetadata?, platformVersionProvider: PlatformVersionProvider diff --git a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift index f8361e473df..32b24c92fc4 100644 --- a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift +++ b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift @@ -106,7 +106,7 @@ final class ClangTargetBuildDescriptionTests: XCTestCase { defaultLocalization: nil, supportedPlatforms: [], dependencies: [], - targets: [target], + targets: .init([target]), products: [], registryMetadata: nil, platformVersionProvider: .init(implementation: .minimumDeploymentTargetDefault)), diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 1b38f1ea6eb..fc83de68471 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -3095,9 +3095,9 @@ final class PackageCommandTests: CommandsTestCase { let execProducts = context.package.products(ofType: ExecutableProduct.self) print("execProducts: \\(execProducts.map{ $0.name })") let swiftTargets = context.package.targets(ofType: SwiftSourceModuleTarget.self) - print("swiftTargets: \\(swiftTargets.map{ $0.name })") + print("swiftTargets: \\(swiftTargets.map{ $0.name }.sorted())") let swiftSources = swiftTargets.flatMap{ $0.sourceFiles(withSuffix: ".swift") } - print("swiftSources: \\(swiftSources.map{ $0.path.lastComponent })") + print("swiftSources: \\(swiftSources.map{ $0.path.lastComponent }.sorted())") if let target = target.sourceModule { print("Module kind of '\\(target.name)': \\(target.kind)") @@ -3161,8 +3161,8 @@ final class PackageCommandTests: CommandsTestCase { do { let (stdout, _) = try SwiftPM.Package.execute(["print-target-dependencies", "--target", "FifthTarget"], packagePath: packageDir) XCTAssertMatch(stdout, .contains("execProducts: [\"FifthTarget\"]")) - XCTAssertMatch(stdout, .contains("swiftTargets: [\"ThirdTarget\", \"TestTarget\", \"SecondTarget\", \"FourthTarget\", \"FirstTarget\", \"FifthTarget\"]")) - XCTAssertMatch(stdout, .contains("swiftSources: [\"library.swift\", \"tests.swift\", \"library.swift\", \"library.swift\", \"library.swift\", \"main.swift\"]")) + XCTAssertMatch(stdout, .contains("swiftTargets: [\"FifthTarget\", \"FirstTarget\", \"FourthTarget\", \"SecondTarget\", \"TestTarget\", \"ThirdTarget\"]")) + XCTAssertMatch(stdout, .contains("swiftSources: [\"library.swift\", \"library.swift\", \"library.swift\", \"library.swift\", \"main.swift\", \"tests.swift\"]")) XCTAssertMatch(stdout, .contains("Module kind of 'FifthTarget': executable")) } From d48db30ec7ad7b1e775f285de75a46eafd2c245f Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Fri, 26 Apr 2024 17:15:16 -0400 Subject: [PATCH 03/14] Fix test targets that depend on macros and `swift-testing` (#7508) After #7353 landed, I noticed that the build products for test targets were not being emitted correctly. swift-testing and XCTest produce separate build products (with distinct names) but this wasn't happening as intended. It turns out that the changes to split `buildParameters` into `productsBuildParameters` and `toolsBuildParameters` weren't fully propagated to our testing infrastructure. I also noticed `SWIFT_PM_SUPPORTS_SWIFT_TESTING` wasn't being set correctly anymore (same root cause) although we've decided to ignore that flag over in swift-testing anyway (see https://github.com/apple/swift-testing/pull/376.) This regression caused build failures in swift-testing (e.g. [here](https://ci.swift.org/job/pr-swift-testing-macos/663/console)) with the telltale failure signature: > /Users/ec2-user/jenkins/workspace/pr-swift-testing-macos/branch-main/swift-testing/.build/x86_64-apple-macosx/debug/swift-testingPackageTests.xctest/Contents/MacOS/swift-testingPackageTests: /Users/ec2-user/jenkins/workspace/pr-swift-testing-macos/branch-main/swift-testing/.build/x86_64-apple-macosx/debug/swift-testingPackageTests.xctest/Contents/MacOS/swift-testingPackageTests: cannot execute binary file Which indicates that it thinks the filename for the swift-testing build product is the XCTest bundle's executable. This PR plumbs through the two build parameters arguments to everywhere in `swift test` and `swift build` that needs them and resolves the issue. --------- Co-authored-by: Max Desiatov (cherry picked from commit 5a4c0240c771db9dab8b5b264a9d368dfe11f0fc) # Conflicts: # Sources/Commands/SwiftBuildCommand.swift # Sources/Commands/SwiftTestCommand.swift # Sources/Commands/Utilities/TestingSupport.swift --- Sources/Commands/SwiftBuildCommand.swift | 8 +- Sources/Commands/SwiftTestCommand.swift | 103 ++++++++++-------- .../Commands/Utilities/TestingSupport.swift | 35 +++++- 3 files changed, 94 insertions(+), 52 deletions(-) diff --git a/Sources/Commands/SwiftBuildCommand.swift b/Sources/Commands/SwiftBuildCommand.swift index 0b6567cfed8..5755fc7429f 100644 --- a/Sources/Commands/SwiftBuildCommand.swift +++ b/Sources/Commands/SwiftBuildCommand.swift @@ -180,21 +180,23 @@ public struct SwiftBuildCommand: AsyncSwiftCommand { library: library ) } + var productsBuildParameters = try swiftCommandState.productsBuildParameters + var toolsBuildParameters = try swiftCommandState.toolsBuildParameters for library in try options.testLibraryOptions.enabledTestingLibraries(swiftCommandState: swiftCommandState) { updateTestingParameters(of: &productsBuildParameters, library: library) updateTestingParameters(of: &toolsBuildParameters, library: library) try build(swiftCommandState, subset: subset, productsBuildParameters: productsBuildParameters, toolsBuildParameters: toolsBuildParameters) } } else { - try build(swiftCommandState, subset: subset, productsBuildParameters: productsBuildParameters, toolsBuildParameters: toolsBuildParameters) + try build(swiftCommandState, subset: subset, productsBuildParameters: nil, toolsBuildParameters: nil) } } private func build( _ swiftCommandState: SwiftCommandState, subset: BuildSubset, - productsBuildParameters: BuildParameters, - toolsBuildParameters: BuildParameters + productsBuildParameters: BuildParameters?, + toolsBuildParameters: BuildParameters? ) throws { let buildSystem = try swiftCommandState.createBuildSystem( explicitProduct: options.product, diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index b955cf4d7c4..48a89e5bbe1 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -236,11 +236,11 @@ public struct SwiftTestCommand: AsyncSwiftCommand { throw TestError.xcodeNotInstalled } - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: .xctest) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: .xctest) // Remove test output from prior runs and validate priors. - if self.options.enableExperimentalTestOutput && buildParameters.triple.supportsTestSummary { - _ = try? localFileSystem.removeFileTree(buildParameters.testOutputPath) + if self.options.enableExperimentalTestOutput && productsBuildParameters.triple.supportsTestSummary { + _ = try? localFileSystem.removeFileTree(productsBuildParameters.testOutputPath) } let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .xctest) @@ -249,7 +249,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { try await runTestProducts( testProducts, additionalArguments: xctestArgs, - buildParameters: buildParameters, + productsBuildParameters: productsBuildParameters, swiftCommandState: swiftCommandState, library: .xctest ) @@ -276,7 +276,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { // Clean out the code coverage directory that may contain stale // profraw files from a previous run of the code coverage tool. if self.options.enableCodeCoverage { - try swiftCommandState.fileSystem.removeFileTree(buildParameters.codeCovPath) + try swiftCommandState.fileSystem.removeFileTree(productsBuildParameters.codeCovPath) } // Run the tests using the parallel runner. @@ -286,7 +286,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { toolchain: toolchain, numJobs: options.numberOfWorkers ?? ProcessInfo.processInfo.activeProcessorCount, buildOptions: globalOptions.build, - buildParameters: buildParameters, + productsBuildParameters: productsBuildParameters, shouldOutputSuccess: swiftCommandState.logLevel <= .info, observabilityScope: swiftCommandState.observabilityScope ) @@ -305,7 +305,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } if self.options.enableExperimentalTestOutput, !runner.ranSuccessfully { - try Self.handleTestOutput(buildParameters: buildParameters, packagePath: testProducts[0].packagePath) + try Self.handleTestOutput(productsBuildParameters: productsBuildParameters, packagePath: testProducts[0].packagePath) } } } @@ -366,13 +366,13 @@ public struct SwiftTestCommand: AsyncSwiftCommand { // MARK: - swift-testing private func swiftTestingRun(_ swiftCommandState: SwiftCommandState) async throws { - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: .swiftTesting) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: .swiftTesting) let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .swiftTesting) let additionalArguments = Array(CommandLine.arguments.dropFirst()) try await runTestProducts( testProducts, additionalArguments: additionalArguments, - buildParameters: buildParameters, + productsBuildParameters: productsBuildParameters, swiftCommandState: swiftCommandState, library: .swiftTesting ) @@ -408,20 +408,20 @@ public struct SwiftTestCommand: AsyncSwiftCommand { private func runTestProducts( _ testProducts: [BuiltTestProduct], additionalArguments: [String], - buildParameters: BuildParameters, + productsBuildParameters: BuildParameters, swiftCommandState: SwiftCommandState, library: BuildParameters.Testing.Library ) async throws { // Clean out the code coverage directory that may contain stale // profraw files from a previous run of the code coverage tool. if self.options.enableCodeCoverage { - try swiftCommandState.fileSystem.removeFileTree(buildParameters.codeCovPath) + try swiftCommandState.fileSystem.removeFileTree(productsBuildParameters.codeCovPath) } let toolchain = try swiftCommandState.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - buildParameters: buildParameters, + destinationBuildParameters: productsBuildParameters, sanitizers: globalOptions.build.sanitizers, library: library ) @@ -451,17 +451,17 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } if self.options.enableExperimentalTestOutput, !ranSuccessfully { - try Self.handleTestOutput(buildParameters: buildParameters, packagePath: testProducts[0].packagePath) + try Self.handleTestOutput(productsBuildParameters: productsBuildParameters, packagePath: testProducts[0].packagePath) } } - private static func handleTestOutput(buildParameters: BuildParameters, packagePath: AbsolutePath) throws { - guard localFileSystem.exists(buildParameters.testOutputPath) else { + private static func handleTestOutput(productsBuildParameters: BuildParameters, packagePath: AbsolutePath) throws { + guard localFileSystem.exists(productsBuildParameters.testOutputPath) else { print("No existing test output found.") return } - let lines = try String(contentsOfFile: buildParameters.testOutputPath.pathString).components(separatedBy: "\n") + let lines = try String(contentsOfFile: productsBuildParameters.testOutputPath.pathString).components(separatedBy: "\n") let events = try lines.map { try JSONDecoder().decode(TestEventRecord.self, from: $0) } let caseEvents = events.compactMap { $0.caseEvent } @@ -505,10 +505,10 @@ public struct SwiftTestCommand: AsyncSwiftCommand { // Merge all the profraw files to produce a single profdata file. try mergeCodeCovRawDataFiles(swiftCommandState: swiftCommandState, library: library) - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) for product in testProducts { // Export the codecov data as JSON. - let jsonPath = buildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName) + let jsonPath = productsBuildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName) try exportCodeCovAsJSON(to: jsonPath, testBinary: product.binaryPath, swiftCommandState: swiftCommandState, library: library) } } @@ -519,18 +519,18 @@ public struct SwiftTestCommand: AsyncSwiftCommand { let llvmProf = try swiftCommandState.getTargetToolchain().getLLVMProf() // Get the profraw files. - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: library) - let codeCovFiles = try swiftCommandState.fileSystem.getDirectoryContents(buildParameters.codeCovPath) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let codeCovFiles = try swiftCommandState.fileSystem.getDirectoryContents(productsBuildParameters.codeCovPath) // Construct arguments for invoking the llvm-prof tool. var args = [llvmProf.pathString, "merge", "-sparse"] for file in codeCovFiles { - let filePath = buildParameters.codeCovPath.appending(component: file) + let filePath = productsBuildParameters.codeCovPath.appending(component: file) if filePath.extension == "profraw" { args.append(filePath.pathString) } } - args += ["-o", buildParameters.codeCovDataFile.pathString] + args += ["-o", productsBuildParameters.codeCovDataFile.pathString] try TSCBasic.Process.checkNonZeroExit(arguments: args) } @@ -544,11 +544,11 @@ public struct SwiftTestCommand: AsyncSwiftCommand { ) throws { // Export using the llvm-cov tool. let llvmCov = try swiftCommandState.getTargetToolchain().getLLVMCov() - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) let args = [ llvmCov.pathString, "export", - "-instr-profile=\(buildParameters.codeCovDataFile)", + "-instr-profile=\(productsBuildParameters.codeCovDataFile)", testBinary.pathString ] let result = try TSCBasic.Process.popen(arguments: args) @@ -567,10 +567,11 @@ public struct SwiftTestCommand: AsyncSwiftCommand { swiftCommandState: SwiftCommandState, library: BuildParameters.Testing.Library ) throws -> [BuiltTestProduct] { - let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: library) + let (productsBuildParameters, toolsBuildParameters) = try swiftCommandState.buildParametersForTest(options: self.options, library: library) return try Commands.buildTestsIfNeeded( swiftCommandState: swiftCommandState, - buildParameters: buildParameters, + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters, testProduct: self.options.sharedOptions.testProduct ) } @@ -620,8 +621,8 @@ extension SwiftTestCommand { guard let rootManifest = rootManifests.values.first else { throw StringError("invalid manifests at \(root.packages)") } - let buildParameters = try swiftCommandState.buildParametersForTest(enableCodeCoverage: true, library: .xctest) - print(buildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName)) + let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(enableCodeCoverage: true, library: .xctest) + print(productsBuildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName)) } } @@ -632,7 +633,7 @@ extension SwiftTestCommand { func run(_ swiftCommandState: SwiftCommandState) throws { try SwiftTestCommand.handleTestOutput( - buildParameters: try swiftCommandState.productsBuildParameters, + productsBuildParameters: try swiftCommandState.productsBuildParameters, packagePath: localFileSystem.currentWorkingDirectory ?? .root // by definition runs in the current working directory ) } @@ -660,12 +661,16 @@ extension SwiftTestCommand { // MARK: - XCTest private func xctestRun(_ swiftCommandState: SwiftCommandState) throws { - let buildParameters = try swiftCommandState.buildParametersForTest( + let (productsBuildParameters, toolsBuildParameters) = try swiftCommandState.buildParametersForTest( enableCodeCoverage: false, shouldSkipBuilding: sharedOptions.shouldSkipBuilding, library: .xctest ) - let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, buildParameters: buildParameters) + let testProducts = try buildTestsIfNeeded( + swiftCommandState: swiftCommandState, + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters + ) let testSuites = try TestingSupport.getTestSuites( in: testProducts, swiftCommandState: swiftCommandState, @@ -684,20 +689,21 @@ extension SwiftTestCommand { // MARK: - swift-testing private func swiftTestingRun(_ swiftCommandState: SwiftCommandState) throws { - let buildParameters = try swiftCommandState.buildParametersForTest( + let (productsBuildParameters, toolsBuildParameters) = try swiftCommandState.buildParametersForTest( enableCodeCoverage: false, shouldSkipBuilding: sharedOptions.shouldSkipBuilding, library: .swiftTesting ) let testProducts = try buildTestsIfNeeded( swiftCommandState: swiftCommandState, - buildParameters: buildParameters + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters ) let toolchain = try swiftCommandState.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - buildParameters: buildParameters, + destinationBuildParameters: productsBuildParameters, sanitizers: globalOptions.build.sanitizers, library: .swiftTesting ) @@ -737,11 +743,13 @@ extension SwiftTestCommand { private func buildTestsIfNeeded( swiftCommandState: SwiftCommandState, - buildParameters: BuildParameters + productsBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters ) throws -> [BuiltTestProduct] { return try Commands.buildTestsIfNeeded( swiftCommandState: swiftCommandState, - buildParameters: buildParameters, + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters, testProduct: self.sharedOptions.testProduct ) } @@ -934,7 +942,7 @@ final class ParallelTestRunner { private let toolchain: UserToolchain private let buildOptions: BuildOptions - private let buildParameters: BuildParameters + private let productsBuildParameters: BuildParameters /// Number of tests to execute in parallel. private let numJobs: Int @@ -951,7 +959,7 @@ final class ParallelTestRunner { toolchain: UserToolchain, numJobs: Int, buildOptions: BuildOptions, - buildParameters: BuildParameters, + productsBuildParameters: BuildParameters, shouldOutputSuccess: Bool, observabilityScope: ObservabilityScope ) { @@ -978,7 +986,7 @@ final class ParallelTestRunner { } self.buildOptions = buildOptions - self.buildParameters = buildParameters + self.productsBuildParameters = productsBuildParameters assert(numJobs > 0, "num jobs should be > 0") } @@ -1008,7 +1016,7 @@ final class ParallelTestRunner { let testEnv = try TestingSupport.constructTestEnvironment( toolchain: self.toolchain, - buildParameters: self.buildParameters, + destinationBuildParameters: self.productsBuildParameters, sanitizers: self.buildOptions.sanitizers, library: .xctest // swift-testing does not use ParallelTestRunner ) @@ -1076,7 +1084,7 @@ final class ParallelTestRunner { // Print test results. for test in processedTests.get() { - if (!test.success || shouldOutputSuccess) && !buildParameters.testingParameters.experimentalTestOutput { + if (!test.success || shouldOutputSuccess) && !productsBuildParameters.testingParameters.experimentalTestOutput { // command's result output goes on stdout // ie "swift test" should output to stdout print(test.output) @@ -1295,7 +1303,7 @@ extension SwiftCommandState { func buildParametersForTest( options: TestCommandOptions, library: BuildParameters.Testing.Library - ) throws -> BuildParameters { + ) throws -> (productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters) { var result = try self.buildParametersForTest( enableCodeCoverage: options.enableCodeCoverage, enableTestability: options.enableTestableImports, @@ -1304,7 +1312,8 @@ extension SwiftCommandState { library: library ) if try options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: self) { - result.flags.swiftCompilerFlags += ["-DSWIFT_PM_SUPPORTS_SWIFT_TESTING"] + result.productsBuildParameters.flags.swiftCompilerFlags += ["-DSWIFT_PM_SUPPORTS_SWIFT_TESTING"] + result.toolsBuildParameters.flags.swiftCompilerFlags += ["-DSWIFT_PM_SUPPORTS_SWIFT_TESTING"] } return result } @@ -1364,10 +1373,14 @@ private extension Basics.Diagnostic { /// - Returns: The paths to the build test products. private func buildTestsIfNeeded( swiftCommandState: SwiftCommandState, - buildParameters: BuildParameters, + productsBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters, testProduct: String? ) throws -> [BuiltTestProduct] { - let buildSystem = try swiftCommandState.createBuildSystem(productsBuildParameters: buildParameters) + let buildSystem = try swiftCommandState.createBuildSystem( + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters + ) let subset = testProduct.map(BuildSubset.product) ?? .allIncludingTests try buildSystem.build(subset: subset) diff --git a/Sources/Commands/Utilities/TestingSupport.swift b/Sources/Commands/Utilities/TestingSupport.swift index 2ba203320b5..c9094c706a5 100644 --- a/Sources/Commands/Utilities/TestingSupport.swift +++ b/Sources/Commands/Utilities/TestingSupport.swift @@ -120,7 +120,7 @@ enum TestingSupport { shouldSkipBuilding: shouldSkipBuilding, experimentalTestOutput: experimentalTestOutput, library: .xctest - ), + ).productsBuildParameters, sanitizers: sanitizers, library: .xctest ) @@ -136,7 +136,7 @@ enum TestingSupport { enableCodeCoverage: enableCodeCoverage, shouldSkipBuilding: shouldSkipBuilding, library: .xctest - ), + ).productsBuildParameters, sanitizers: sanitizers, library: .xctest ) @@ -223,8 +223,35 @@ extension SwiftCommandState { shouldSkipBuilding: Bool = false, experimentalTestOutput: Bool = false, library: BuildParameters.Testing.Library - ) throws -> BuildParameters { - var parameters = try self.productsBuildParameters + ) throws -> (productsBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters) { + let productsBuildParameters = buildParametersForTest( + modifying: try productsBuildParameters, + enableCodeCoverage: enableCodeCoverage, + enableTestability: enableTestability, + shouldSkipBuilding: shouldSkipBuilding, + experimentalTestOutput: experimentalTestOutput, + library: library + ) + let toolsBuildParameters = buildParametersForTest( + modifying: try toolsBuildParameters, + enableCodeCoverage: enableCodeCoverage, + enableTestability: enableTestability, + shouldSkipBuilding: shouldSkipBuilding, + experimentalTestOutput: experimentalTestOutput, + library: library + ) + return (productsBuildParameters, toolsBuildParameters) + } + + private func buildParametersForTest( + modifying parameters: BuildParameters, + enableCodeCoverage: Bool, + enableTestability: Bool?, + shouldSkipBuilding: Bool, + experimentalTestOutput: Bool, + library: BuildParameters.Testing.Library + ) -> BuildParameters { + var parameters = parameters var explicitlyEnabledDiscovery = false var explicitlySpecifiedPath: AbsolutePath? From e27b9f039fbc2cc7f2b430eb08ea2777734dfc7a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 6 Jun 2024 11:58:35 +0100 Subject: [PATCH 04/14] Fix merge conflict build issues --- Sources/Commands/SwiftTestCommand.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index 48a89e5bbe1..9f8c3bdd96e 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -421,7 +421,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { let toolchain = try swiftCommandState.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - destinationBuildParameters: productsBuildParameters, + buildParameters: productsBuildParameters, sanitizers: globalOptions.build.sanitizers, library: library ) @@ -703,7 +703,7 @@ extension SwiftTestCommand { let toolchain = try swiftCommandState.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - destinationBuildParameters: productsBuildParameters, + buildParameters: productsBuildParameters, sanitizers: globalOptions.build.sanitizers, library: .swiftTesting ) @@ -1016,7 +1016,7 @@ final class ParallelTestRunner { let testEnv = try TestingSupport.constructTestEnvironment( toolchain: self.toolchain, - destinationBuildParameters: self.productsBuildParameters, + buildParameters: self.productsBuildParameters, sanitizers: self.buildOptions.sanitizers, library: .xctest // swift-testing does not use ParallelTestRunner ) From 287f03b9e247524b2a4be7e8b0d020e8220de6b1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 1 May 2024 19:02:42 +0100 Subject: [PATCH 05/14] Fix incorrect paths for library products with explicit linkage (#7519) Library products declared with `.static` or `.dynamic` linkage didn't have a `-tools` suffix in their file names when built as dependencies of macros. This change resolves the inconsistency and adds corresponding build plan tests. The regression in question broke the compatibility test suite, which had [an old version of `swift-power-assert`](https://github.com/kishikawakatsumi/swift-power-assert/blob/a60cb50/Package.swift) depending on an old version of `swift-syntax` with explicit `.static` linkage for its products. rdar://127170225 (cherry picked from commit 8db240186de97b01c2d2fb351b367bbdd43fe6b6) # Conflicts: # Tests/BuildTests/CrossCompilationBuildPlanTests.swift --- .../BuildParameters/BuildParameters.swift | 4 +- .../SPMTestSupport/MockPackageGraphs.swift | 68 ++++++++++++++++++- .../CrossCompilationBuildPlanTests.swift | 55 ++++++++++++--- .../CrossCompilationPackageGraphTests.swift | 2 +- 4 files changed, 116 insertions(+), 13 deletions(-) diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index 02902339324..baf1e966d1a 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -243,7 +243,7 @@ public struct BuildParameters: Encodable { /// Returns the path to the dynamic library of a product for the current build parameters. func potentialDynamicLibraryPath(for product: ResolvedProduct) throws -> RelativePath { - try RelativePath(validating: "\(self.triple.dynamicLibraryPrefix)\(product.name)\(self.triple.dynamicLibraryExtension)") + try RelativePath(validating: "\(self.triple.dynamicLibraryPrefix)\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.dynamicLibraryExtension)") } /// Returns the path to the binary of a product for the current build parameters, relative to the build directory. @@ -254,7 +254,7 @@ public struct BuildParameters: Encodable { case .executable, .snippet: return potentialExecutablePath case .library(.static): - return try RelativePath(validating: "lib\(product.name)\(self.triple.staticLibraryExtension)") + return try RelativePath(validating: "lib\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.staticLibraryExtension)") case .library(.dynamic): return try potentialDynamicLibraryPath(for: product) case .library(.automatic), .plugin: diff --git a/Sources/SPMTestSupport/MockPackageGraphs.swift b/Sources/SPMTestSupport/MockPackageGraphs.swift index 1f3f956e23a..1833db62c82 100644 --- a/Sources/SPMTestSupport/MockPackageGraphs.swift +++ b/Sources/SPMTestSupport/MockPackageGraphs.swift @@ -16,6 +16,7 @@ import class Basics.ObservabilityScope import struct PackageGraph.ModulesGraph import class PackageModel.Manifest import struct PackageModel.ProductDescription +import enum PackageModel.ProductType import struct PackageModel.TargetDescription import protocol TSCBasic.FileSystem import class TSCBasic.InMemoryFileSystem @@ -253,7 +254,7 @@ package func macrosTestsPackageGraph() throws -> MockPackageGraph { return (graph, fs, observability.topScope) } -package func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { +package func trivialPackageGraph() throws -> MockPackageGraph { let fs = InMemoryFileSystem( emptyFiles: "/Pkg/Sources/app/main.swift", @@ -283,7 +284,7 @@ package func trivialPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackag return (graph, fs, observability.topScope) } -package func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> MockPackageGraph { +package func embeddedCxxInteropPackageGraph() throws -> MockPackageGraph { let fs = InMemoryFileSystem( emptyFiles: "/Pkg/Sources/app/main.swift", @@ -324,3 +325,66 @@ package func embeddedCxxInteropPackageGraph(pkgRootPath: AbsolutePath) throws -> return (graph, fs, observability.topScope) } + +package func toolsExplicitLibrariesGraph(linkage: ProductType.LibraryType) throws -> MockPackageGraph { + let fs = InMemoryFileSystem(emptyFiles: + "/swift-mmio/Sources/MMIOMacros/source.swift", + "/swift-mmio/Sources/MMIOMacrosTests/source.swift", + "/swift-syntax/Sources/SwiftSyntax/source.swift" + ) + + let observability = ObservabilitySystem.makeForTesting() + let graph = try loadModulesGraph( + fileSystem: fs, + manifests: [ + Manifest.createRootManifest( + displayName: "swift-mmio", + path: "/swift-mmio", + dependencies: [ + .localSourceControl( + path: "/swift-syntax", + requirement: .upToNextMajor(from: "1.0.0") + ) + ], + targets: [ + TargetDescription( + name: "MMIOMacros", + dependencies: [ + .product(name: "SwiftSyntax", package: "swift-syntax"), + ], + type: .macro + ), + TargetDescription( + name: "MMIOMacrosTests", + dependencies: [ + .target(name: "MMIOMacros"), + ], + type: .test + ) + ] + ), + Manifest.createFileSystemManifest( + displayName: "swift-syntax", + path: "/swift-syntax", + products: [ + ProductDescription( + name: "SwiftSyntax", + type: .library(linkage), + targets: ["SwiftSyntax"] + ), + ], + targets: [ + TargetDescription( + name: "SwiftSyntax", + dependencies: [] + ), + ] + ), + ], + observabilityScope: observability.topScope + ) + + XCTAssertNoDiagnostics(observability.diagnostics) + + return (graph, fs, observability.topScope) +} diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 56d6bb9cabb..3075a1f4c77 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -20,6 +20,7 @@ import struct Basics.Triple import enum PackageGraph.BuildTriple import class PackageModel.Manifest import struct PackageModel.TargetDescription +import enum PackageModel.ProductType import func SPMTestSupport.loadPackageGraph @_spi(SwiftPMInternal) @@ -29,8 +30,7 @@ import func SPMTestSupport.embeddedCxxInteropPackageGraph import func SPMTestSupport.macrosPackageGraph import func SPMTestSupport.macrosTestsPackageGraph import func SPMTestSupport.mockBuildParameters - -@_spi(SwiftPMInternal) +import func SPMTestSupport.toolsExplicitLibrariesGraph import func SPMTestSupport.trivialPackageGraph import struct SPMTestSupport.BuildPlanResult @@ -42,7 +42,7 @@ import XCTest final class CrossCompilationBuildPlanTests: XCTestCase { func testEmbeddedWasmTarget() throws { - var (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: "/Pkg") + var (graph, fs, observabilityScope) = try trivialPackageGraph() let triple = try Triple("wasm32-unknown-none-wasm") var parameters = mockBuildParameters(triple: triple) @@ -73,7 +73,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { ] ) - (graph, fs, observabilityScope) = try embeddedCxxInteropPackageGraph(pkgRootPath: "/Pkg") + (graph, fs, observabilityScope) = try embeddedCxxInteropPackageGraph() result = try BuildPlanResult(plan: BuildPlan( buildParameters: parameters, @@ -103,9 +103,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { } func testWasmTargetRelease() throws { - let pkgPath = AbsolutePath("/Pkg") - - let (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: pkgPath) + let (graph, fs, observabilityScope) = try trivialPackageGraph() var parameters = mockBuildParameters( config: .release, triple: .wasi, linkerDeadStrip: true @@ -138,7 +136,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { func testWASITarget() throws { let pkgPath = AbsolutePath("/Pkg") - let (graph, fs, observabilityScope) = try trivialPackageGraph(pkgRootPath: pkgPath) + let (graph, fs, observabilityScope) = try trivialPackageGraph() var parameters = mockBuildParameters(triple: .wasi) parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true @@ -311,6 +309,47 @@ final class CrossCompilationBuildPlanTests: XCTestCase { ] ) } + + func testToolsExplicitLibraries() throws { + let destinationTriple = Triple.arm64Linux + let toolsTriple = Triple.x86_64MacOS + + for (linkage, productFileName) in [(ProductType.LibraryType.static, "libSwiftSyntax-tool.a"), (.dynamic, "libSwiftSyntax-tool.dylib")] { + let (graph, fs, scope) = try toolsExplicitLibrariesGraph(linkage: linkage) + let plan = try BuildPlan( + destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), + toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + graph: graph, + fileSystem: fs, + observabilityScope: scope + ) + let result = try BuildPlanResult(plan: plan) + result.checkProductsCount(4) + result.checkTargetsCount(6) + + XCTAssertTrue(try result.allTargets(named: "SwiftSyntax") + .map { try $0.swiftTarget() } + .contains { $0.target.buildTriple == .tools }) + + try result.check(buildTriple: .tools, triple: toolsTriple, for: "swift-mmioPackageTests") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "swift-mmioPackageDiscoveredTests") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "MMIOMacros") + try result.check(buildTriple: .tools, triple: toolsTriple, for: "MMIOMacrosTests") + + let macroProducts = result.allProducts(named: "MMIOMacros") + XCTAssertEqual(macroProducts.count, 1) + let macroProduct = try XCTUnwrap(macroProducts.first) + XCTAssertEqual(macroProduct.buildParameters.triple, toolsTriple) + + let swiftSyntaxProducts = result.allProducts(named: "SwiftSyntax") + XCTAssertEqual(swiftSyntaxProducts.count, 2) + let swiftSyntaxToolsProduct = try XCTUnwrap(swiftSyntaxProducts.first { $0.product.buildTriple == .tools }) + let archiveArguments = try swiftSyntaxToolsProduct.archiveArguments() + + // Verify that produced library file has a correct name + XCTAssertMatch(archiveArguments, [.contains(productFileName)]) + } + } } extension BuildPlanResult { diff --git a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift index dc50bab88c7..69c19852f59 100644 --- a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift +++ b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift @@ -20,7 +20,7 @@ import XCTest final class CrossCompilationPackageGraphTests: XCTestCase { func testTrivialPackage() throws { - let graph = try trivialPackageGraph(pkgRootPath: "/Pkg").graph + let graph = try trivialPackageGraph().graph try PackageGraphTester(graph) { result in result.check(packages: "Pkg") // "SwiftSyntax" is included for both host and target triples and is not pruned on this level From 16d2384a4439988c0f72334662184b1b82a4a9b4 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 6 Jun 2024 12:14:42 +0100 Subject: [PATCH 06/14] Fix Linux conflict resolution build issue --- Sources/Commands/Utilities/TestingSupport.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Commands/Utilities/TestingSupport.swift b/Sources/Commands/Utilities/TestingSupport.swift index c9094c706a5..d4314eb0727 100644 --- a/Sources/Commands/Utilities/TestingSupport.swift +++ b/Sources/Commands/Utilities/TestingSupport.swift @@ -132,7 +132,7 @@ enum TestingSupport { #else let env = try Self.constructTestEnvironment( toolchain: try swiftCommandState.getTargetToolchain(), - destinationBuildParameters: swiftCommandState.buildParametersForTest( + buildParameters: swiftCommandState.buildParametersForTest( enableCodeCoverage: enableCodeCoverage, shouldSkipBuilding: shouldSkipBuilding, library: .xctest From fab1e2b47ee73217da65b407c15a84426d88bdfa Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 6 Jun 2024 15:58:08 +0100 Subject: [PATCH 07/14] Remove unrelated test This test should be cherry-picked in https://github.com/apple/swift-package-manager/pull/7641 and initially ended up in this cherry-pick PR by mistake. --- .../ClangTargetBuildDescriptionTests.swift | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift index 32b24c92fc4..88f91f2ddde 100644 --- a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift +++ b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift @@ -25,27 +25,6 @@ final class ClangTargetBuildDescriptionTests: XCTestCase { XCTAssertFalse(try targetDescription.basicArguments().contains("-w")) } - func testSwiftCorelibsFoundationIncludeWorkaround() throws { - let toolchain = MockToolchain(swiftResourcesPath: AbsolutePath("/fake/path/lib/swift")) - - let macosParameters = mockBuildParameters(toolchain: toolchain, triple: .macOS) - let linuxParameters = mockBuildParameters(toolchain: toolchain, triple: .arm64Linux) - let androidParameters = mockBuildParameters(toolchain: toolchain, triple: .arm64Android) - - let macDescription = try makeTargetBuildDescription("swift-corelibs-foundation", - buildParameters: macosParameters) - XCTAssertFalse(try macDescription.basicArguments().contains("\(macosParameters.toolchain.swiftResourcesPath!)")) - - let linuxDescription = try makeTargetBuildDescription("swift-corelibs-foundation", - buildParameters: linuxParameters) - print(try linuxDescription.basicArguments()) - XCTAssertTrue(try linuxDescription.basicArguments().contains("\(linuxParameters.toolchain.swiftResourcesPath!)")) - - let androidDescription = try makeTargetBuildDescription("swift-corelibs-foundation", - buildParameters: androidParameters) - XCTAssertTrue(try androidDescription.basicArguments().contains("\(androidParameters.toolchain.swiftResourcesPath!)")) - } - func testWarningSuppressionForRemotePackages() throws { let targetDescription = try makeTargetBuildDescription("test-warning-supression", usesSourceControl: true) XCTAssertTrue(try targetDescription.basicArguments().contains("-w")) From c208c33a8273839cb7df75aedd4ff1d59e3ea7a1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 6 Jun 2024 18:05:45 +0100 Subject: [PATCH 08/14] Fix comment wording --- Sources/Commands/SwiftTestCommand.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index 9f8c3bdd96e..d53f1354143 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -295,7 +295,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { try generateXUnitOutputIfRequested(for: testResults, swiftCommandState: swiftCommandState) - // process code Coverage if request + // Process code coverage if requested if self.options.enableCodeCoverage, runner.ranSuccessfully { try await processCodeCoverage(testProducts, swiftCommandState: swiftCommandState, library: .xctest) } From a9c04c47edf8a60b746d98446e0cf2d9cb2a258c Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Thu, 6 Jun 2024 17:41:14 -0700 Subject: [PATCH 09/14] Fix up merge resolution of `Sources/Commands/SwiftBuildCommand.swift` --- Sources/Commands/SwiftBuildCommand.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Sources/Commands/SwiftBuildCommand.swift b/Sources/Commands/SwiftBuildCommand.swift index 5755fc7429f..0b6567cfed8 100644 --- a/Sources/Commands/SwiftBuildCommand.swift +++ b/Sources/Commands/SwiftBuildCommand.swift @@ -180,23 +180,21 @@ public struct SwiftBuildCommand: AsyncSwiftCommand { library: library ) } - var productsBuildParameters = try swiftCommandState.productsBuildParameters - var toolsBuildParameters = try swiftCommandState.toolsBuildParameters for library in try options.testLibraryOptions.enabledTestingLibraries(swiftCommandState: swiftCommandState) { updateTestingParameters(of: &productsBuildParameters, library: library) updateTestingParameters(of: &toolsBuildParameters, library: library) try build(swiftCommandState, subset: subset, productsBuildParameters: productsBuildParameters, toolsBuildParameters: toolsBuildParameters) } } else { - try build(swiftCommandState, subset: subset, productsBuildParameters: nil, toolsBuildParameters: nil) + try build(swiftCommandState, subset: subset, productsBuildParameters: productsBuildParameters, toolsBuildParameters: toolsBuildParameters) } } private func build( _ swiftCommandState: SwiftCommandState, subset: BuildSubset, - productsBuildParameters: BuildParameters?, - toolsBuildParameters: BuildParameters? + productsBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters ) throws { let buildSystem = try swiftCommandState.createBuildSystem( explicitProduct: options.product, From a3541b8a67a3f385427387c316a78ae78a1dcee5 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Wed, 29 May 2024 18:35:44 +0900 Subject: [PATCH 10/14] Place build.db under the scratch directory (#7471) The build database should be shared between different triple builds to re-generate the build manifest correctly. With the current implementation, the following build command sequence fails: ``` $ swift build --experimental-swift-sdk wasm32-unknown-wasi $ swift build $ swift build --experimental-swift-sdk wasm32-unknown-wasi $ swift build $ swift build --experimental-swift-sdk wasm32-unknown-wasi ``` This changes the llbuild build database to be placed under `.build/build.db` instead of `.build//build.db`. Also this change splits llbuild target names for each triple to avoid cache invalidation when switching triple. `build.db` will be shared across product target triples, and SwiftPM will keep consistent cache state when switching triples. (cherry picked from commit e9399c20bab8c53b77dd6ed1529f68eb47dc4daf) --- .../LLBuildManifestBuilder.swift | 21 +-- Sources/Build/BuildOperation.swift | 8 +- Sources/CoreCommands/BuildSystemSupport.swift | 1 + Sources/swift-bootstrap/main.swift | 1 + Tests/BuildTests/BuildOperationTests.swift | 135 ++++++++++++++++-- Tests/BuildTests/BuildPlanTests.swift | 7 +- .../LLBuildManifestBuilderTests.swift | 22 +-- 7 files changed, 158 insertions(+), 37 deletions(-) diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift index 87f998312bf..d1bf1f5f7c3 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -317,33 +317,34 @@ extension TargetBuildDescription { } extension ResolvedModule { - package func getCommandName(buildParameters: BuildParameters) -> String { + public func getCommandName(buildParameters: BuildParameters) -> String { "C." + self.getLLBuildTargetName(buildParameters: buildParameters) } - package func getLLBuildTargetName(buildParameters: BuildParameters) -> String { - "\(self.name)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module" + public func getLLBuildTargetName(buildParameters: BuildParameters) -> String { + "\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module" } - package func getLLBuildResourcesCmdName(buildParameters: BuildParameters) -> String { - "\(self.name)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module-resources" + public func getLLBuildResourcesCmdName(buildParameters: BuildParameters) -> String { + "\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module-resources" } } extension ResolvedProduct { - package func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String { + public func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String { + let triple = buildParameters.triple.tripleString let config = buildParameters.buildConfig let suffix = buildParameters.suffix(triple: self.buildTriple) - let potentialExecutableTargetName = "\(name)-\(config)\(suffix).exe" - let potentialLibraryTargetName = "\(name)-\(config)\(suffix).dylib" + let potentialExecutableTargetName = "\(name)-\(triple)-\(config)\(suffix).exe" + let potentialLibraryTargetName = "\(name)-\(triple)-\(config)\(suffix).dylib" switch type { case .library(.dynamic): return potentialLibraryTargetName case .test: - return "\(name)-\(config)\(suffix).test" + return "\(name)-\(triple)-\(config)\(suffix).test" case .library(.static): - return "\(name)-\(config)\(suffix).a" + return "\(name)-\(triple)-\(config)\(suffix).a" case .library(.automatic): throw InternalError("automatic library not supported") case .executable, .snippet: diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 0882286eaf7..97d43ba2ea1 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -52,6 +52,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS /// the plugin configuration for build plugins let pluginConfiguration: PluginConfiguration? + /// The path to scratch space (.build) directory. + let scratchDirectory: AbsolutePath + /// The llbuild build delegate reference. private var buildSystemDelegate: BuildOperationBuildSystemDelegateHandler? @@ -114,6 +117,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS cacheBuildManifest: Bool, packageGraphLoader: @escaping () throws -> ModulesGraph, pluginConfiguration: PluginConfiguration? = .none, + scratchDirectory: AbsolutePath, additionalFileRules: [FileRuleDescription], pkgConfigDirectories: [AbsolutePath], dependenciesByRootPackageIdentity: [PackageIdentity: [PackageIdentity]], @@ -136,6 +140,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS self.packageGraphLoader = packageGraphLoader self.additionalFileRules = additionalFileRules self.pluginConfiguration = pluginConfiguration + self.scratchDirectory = scratchDirectory self.pkgConfigDirectories = pkgConfigDirectories self.dependenciesByRootPackageIdentity = dependenciesByRootPackageIdentity self.rootPackageIdentityByTargetName = (try? Dictionary(throwingUniqueKeysWithValues: targetsByRootPackageIdentity.lazy.flatMap { e in e.value.map { ($0, e.key) } })) ?? [:] @@ -554,6 +559,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS toolsBuildParameters: pluginsBuildParameters, cacheBuildManifest: false, packageGraphLoader: { buildToolsGraph }, + scratchDirectory: pluginsBuildParameters.dataPath, additionalFileRules: self.additionalFileRules, pkgConfigDirectories: self.pkgConfigDirectories, dependenciesByRootPackageIdentity: [:], @@ -724,7 +730,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS ) self.buildSystemDelegate = buildSystemDelegate - let databasePath = self.productsBuildParameters.dataPath.appending("build.db").pathString + let databasePath = self.scratchDirectory.appending("build.db").pathString let buildSystem = SPMLLBuild.BuildSystem( buildFile: self.productsBuildParameters.llbuildManifest.pathString, databaseFile: databasePath, diff --git a/Sources/CoreCommands/BuildSystemSupport.swift b/Sources/CoreCommands/BuildSystemSupport.swift index 6106759a4e7..5d7d82e262f 100644 --- a/Sources/CoreCommands/BuildSystemSupport.swift +++ b/Sources/CoreCommands/BuildSystemSupport.swift @@ -49,6 +49,7 @@ private struct NativeBuildSystemFactory: BuildSystemFactory { workDirectory: try self.swiftCommandState.getActiveWorkspace().location.pluginWorkingDirectory, disableSandbox: self.swiftCommandState.shouldDisableSandbox ), + scratchDirectory: self.swiftCommandState.scratchDirectory, additionalFileRules: FileRuleDescription.swiftpmFileTypes, pkgConfigDirectories: self.swiftCommandState.options.locations.pkgConfigDirectories, dependenciesByRootPackageIdentity: rootPackageInfo.dependencies, diff --git a/Sources/swift-bootstrap/main.swift b/Sources/swift-bootstrap/main.swift index 03d505d269d..e6f91509dfd 100644 --- a/Sources/swift-bootstrap/main.swift +++ b/Sources/swift-bootstrap/main.swift @@ -319,6 +319,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand { toolsBuildParameters: buildParameters, cacheBuildManifest: false, packageGraphLoader: packageGraphLoader, + scratchDirectory: scratchDirectory, additionalFileRules: [], pkgConfigDirectories: [], dependenciesByRootPackageIdentity: [:], diff --git a/Tests/BuildTests/BuildOperationTests.swift b/Tests/BuildTests/BuildOperationTests.swift index 6a703ded853..d04cb83fea9 100644 --- a/Tests/BuildTests/BuildOperationTests.swift +++ b/Tests/BuildTests/BuildOperationTests.swift @@ -14,34 +14,62 @@ @testable import PackageModel import Basics +import LLBuildManifest +@_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) +import PackageGraph +import SPMBuildCore import SPMTestSupport import XCTest import class TSCBasic.BufferedOutputByteStream import class TSCBasic.InMemoryFileSystem +private func mockBuildOperation( + productsBuildParameters: BuildParameters, + toolsBuildParameters: BuildParameters, + cacheBuildManifest: Bool = false, + packageGraphLoader: @escaping () -> ModulesGraph = { fatalError() }, + scratchDirectory: AbsolutePath, + fs: any Basics.FileSystem, + observabilityScope: ObservabilityScope +) -> BuildOperation { + return BuildOperation( + productsBuildParameters: productsBuildParameters, + toolsBuildParameters: toolsBuildParameters, + cacheBuildManifest: cacheBuildManifest, + packageGraphLoader: packageGraphLoader, + scratchDirectory: scratchDirectory, + additionalFileRules: [], + pkgConfigDirectories: [], + dependenciesByRootPackageIdentity: [:], + targetsByRootPackageIdentity: [:], + outputStream: BufferedOutputByteStream(), + logLevel: .info, + fileSystem: fs, + observabilityScope: observabilityScope + ) +} + final class BuildOperationTests: XCTestCase { func testDetectUnexpressedDependencies() throws { - let buildParameters = mockBuildParameters(shouldDisableLocalRpath: false) + let scratchDirectory = AbsolutePath("/path/to/build") + let triple = hostTriple + let buildParameters = mockBuildParameters( + buildPath: scratchDirectory.appending(triple.tripleString), + shouldDisableLocalRpath: false, + triple: triple + ) let fs = InMemoryFileSystem(files: [ "\(buildParameters.dataPath)/debug/Lunch.build/Lunch.d" : "/Best.framework" ]) let observability = ObservabilitySystem.makeForTesting() - let buildOp = BuildOperation( + let buildOp = mockBuildOperation( productsBuildParameters: buildParameters, toolsBuildParameters: buildParameters, - cacheBuildManifest: false, - packageGraphLoader: { fatalError() }, - additionalFileRules: [], - pkgConfigDirectories: [], - dependenciesByRootPackageIdentity: [:], - targetsByRootPackageIdentity: [:], - outputStream: BufferedOutputByteStream(), - logLevel: .info, - fileSystem: fs, - observabilityScope: observability.topScope + scratchDirectory: scratchDirectory, + fs: fs, observabilityScope: observability.topScope ) buildOp.detectUnexpressedDependencies( availableLibraries: [ @@ -62,4 +90,87 @@ final class BuildOperationTests: XCTestCase { ["target 'Lunch' has an unexpressed depedency on 'foo'"] ) } + + func testDetectProductTripleChange() throws { + let observability = ObservabilitySystem.makeForTesting() + let fs = InMemoryFileSystem( + emptyFiles: "/Pkg/Sources/ATarget/foo.swift" + ) + let packageGraph = try loadModulesGraph( + fileSystem: fs, + manifests: [ + .createRootManifest( + displayName: "SwitchTriple", + path: "/Pkg", + targets: [ + TargetDescription(name: "ATarget"), + ] + ), + ], + observabilityScope: observability.topScope + ) + try withTemporaryDirectory { tmpDir in + let scratchDirectory = tmpDir.appending(".build") + let fs = localFileSystem + let triples = try [Triple("x86_64-unknown-linux-gnu"), Triple("wasm32-unknown-wasi")] + var llbuildManifestByTriple: [String: String] = [:] + + // Perform initial builds for each triple + for triple in triples { + let buildParameters = mockBuildParameters( + buildPath: scratchDirectory.appending(triple.tripleString), + config: .debug, + triple: triple + ) + let buildOp = mockBuildOperation( + productsBuildParameters: buildParameters, + toolsBuildParameters: buildParameters, + cacheBuildManifest: false, + packageGraphLoader: { packageGraph }, + scratchDirectory: scratchDirectory, + fs: fs, observabilityScope: observability.topScope + ) + // Generate initial llbuild manifest + let _ = try buildOp.getBuildDescription() + // Record the initial llbuild manifest as expected one + llbuildManifestByTriple[triple.tripleString] = try fs.readFileContents(buildParameters.llbuildManifest) + } + + XCTAssertTrue(fs.exists(scratchDirectory.appending("debug.yaml"))) + // FIXME: There should be a build database with manifest cache after the initial build. + // The initial build usually triggered with `cacheBuildManifest=false` because llbuild + // manifest file and description.json are not found. However, with `cacheBuildManifest=false`, + // `BuildOperation` does not trigger "PackageStructure" build, thus the initial build does + // not record the manifest cache. So "getBuildDescription" doesn't create build.db for the + // initial planning and the second build always need full-planning. + // + // XCTAssertTrue(fs.exists(scratchDirectory.appending("build.db"))) + + // Perform incremental build several times and switch triple for each time + for _ in 0..<4 { + for triple in triples { + let buildParameters = mockBuildParameters( + buildPath: scratchDirectory.appending(triple.tripleString), + config: .debug, + triple: triple + ) + let buildOp = mockBuildOperation( + productsBuildParameters: buildParameters, + toolsBuildParameters: buildParameters, + cacheBuildManifest: true, + packageGraphLoader: { packageGraph }, + scratchDirectory: scratchDirectory, + fs: fs, observabilityScope: observability.topScope + ) + // Generate llbuild manifest + let _ = try buildOp.getBuildDescription() + + // Ensure that llbuild manifest is updated to the expected one + let actualManifest: String = try fs.readFileContents(buildParameters.llbuildManifest) + let expectedManifest = try XCTUnwrap(llbuildManifestByTriple[triple.tripleString]) + XCTAssertEqual(actualManifest, expectedManifest) + } + } + } + } } diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index ea5452b4ab4..1ce5cb19fc4 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -5225,12 +5225,13 @@ final class BuildPlanTests: XCTestCase { try llbuild.generateManifest(at: yaml) let contents: String = try fs.readFileContents(yaml) + let triple = result.plan.destinationBuildParameters.triple.tripleString if result.plan.destinationBuildParameters.triple.isWindows() { XCTAssertMatch( contents, .contains(""" - "C.rary-debug.a": + "C.rary-\(triple)-debug.a": tool: shell inputs: ["\( buildPath.appending(components: "rary.build", "rary.swift.o") @@ -5261,7 +5262,7 @@ final class BuildPlanTests: XCTestCase { contents, .contains( """ - "C.rary-debug.a": + "C.rary-\(triple)-debug.a": tool: shell inputs: ["\( buildPath.appending(components: "rary.build", "rary.swift.o") @@ -5289,7 +5290,7 @@ final class BuildPlanTests: XCTestCase { contents, .contains( """ - "C.rary-debug.a": + "C.rary-\(triple)-debug.a": tool: shell inputs: ["\( buildPath.appending(components: "rary.build", "rary.swift.o") diff --git a/Tests/BuildTests/LLBuildManifestBuilderTests.swift b/Tests/BuildTests/LLBuildManifestBuilderTests.swift index b298e6e43a6..5ef41c5e8a8 100644 --- a/Tests/BuildTests/LLBuildManifestBuilderTests.swift +++ b/Tests/BuildTests/LLBuildManifestBuilderTests.swift @@ -72,8 +72,8 @@ final class LLBuildManifestBuilderTests: XCTestCase { var basicReleaseCommandNames = [ AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-release.exe", + "", + "C.exe-\(buildParameters.triple)-release.exe", ] XCTAssertEqual( @@ -101,11 +101,11 @@ final class LLBuildManifestBuilderTests: XCTestCase { llbuild = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: observability.topScope) try llbuild.createProductCommand(buildProduct) - let entitlementsCommandName = "C.exe-debug.exe-entitlements" + let entitlementsCommandName = "C.exe-\(buildParameters.triple)-debug.exe-entitlements" var basicDebugCommandNames = [ AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-debug.exe", + "", + "C.exe-\(buildParameters.triple)-debug.exe", ] XCTAssertEqual( @@ -131,7 +131,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { XCTAssertEqual( entitlementsCommand.outputs, [ - .virtual("exe-debug.exe-CodeSigning"), + .virtual("exe-\(buildParameters.triple)-debug.exe-CodeSigning"), ] ) @@ -157,8 +157,8 @@ final class LLBuildManifestBuilderTests: XCTestCase { basicReleaseCommandNames = [ AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-release.exe", + "", + "C.exe-\(buildParameters.triple)-release.exe", ] XCTAssertEqual( @@ -188,8 +188,8 @@ final class LLBuildManifestBuilderTests: XCTestCase { basicDebugCommandNames = [ AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-debug.exe", + "", + "C.exe-\(buildParameters.triple)-debug.exe", ] XCTAssertEqual( @@ -215,6 +215,6 @@ final class LLBuildManifestBuilderTests: XCTestCase { let builder = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: scope) let manifest = try builder.generateManifest(at: "/manifest") - XCTAssertNotNil(manifest.commands["C.SwiftSyntax-debug-tool.module"]) + XCTAssertNotNil(manifest.commands["C.SwiftSyntax-aarch64-unknown-linux-gnu-debug-tool.module"]) } } From 301ee13f2b1aa809b6bf14895150ad5a0c3543b4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 16 May 2024 17:44:47 -0700 Subject: [PATCH 11/14] Cross compilation improvements A collection of fixes and improvements related to cross-compilation. An attempt to make cross-compilation support more robust, consistent, error-prone and deal with performance regressions related to plugins. - `BuildParameters` are now associated with a destination (host or target) to make sure that they are always used in accordance with their original purpose. - `Buildset` gains a default `for:` parameter to indicate the intended destination of a product/target - LLBuild names for products and modules are computed based on the build parameters instead of relying on `buildTriple` of an product/target - Adds a way to get a command and llbuild name from a build description instead of having to reach for an underlying resolved module/product and pass parameters to it - Refactors most of the uses of `allTargets` and `allProducts` to use the graph and supply an intended destination - `SwiftTargetBuildDescription` no longer needs to reference `toolsBuildParameters` by reworking the way requires macros are referenced - Removes `ModulesGraph.updateBuildTripleRecursively` - Plugins: - Fixes a bug where graph doesn't get a "tools" product synthesized for an executable target referenced by a plugin - Fixes a bug where plugin outputs weren't added to test targets that a rebuilt for "tools" - Tests: - Introduces a new convenient way to mock build plans that respects tools/destination separation of parameters - Adds a "destination" parameter to `check{Target, Product}` default to `.destination` - `swift build` with `--target` and `--product` now behave consistently - performance regression related to plugins has been fixed - It should be harder to request product/target without a destination --- .../BuildDescription/PluginDescription.swift | 4 + .../ResolvedModule+BuildDescription.swift | 2 +- .../SwiftTargetBuildDescription.swift | 121 +++-- .../TargetBuildDescription.swift | 2 +- .../LLBuildManifestBuilder+Clang.swift | 2 +- .../LLBuildManifestBuilder+Product.swift | 54 ++- .../LLBuildManifestBuilder+Resources.swift | 2 +- .../LLBuildManifestBuilder+Swift.swift | 61 +-- .../LLBuildManifestBuilder.swift | 51 +-- Sources/Build/BuildOperation.swift | 156 ++++--- ...dOperationBuildSystemDelegateHandler.swift | 16 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 4 +- Sources/Build/BuildPlan/BuildPlan+Test.swift | 40 +- Sources/Build/BuildPlan/BuildPlan.swift | 41 +- .../PackageCommands/DumpCommands.swift | 1 + .../PackageCommands/PluginCommand.swift | 19 +- .../Commands/Snippets/Cards/SnippetCard.swift | 2 +- Sources/Commands/SwiftRunCommand.swift | 7 +- Sources/Commands/SwiftTestCommand.swift | 7 +- .../Commands/Utilities/PluginDelegate.swift | 3 +- .../Utilities/SymbolGraphExtract.swift | 2 +- Sources/CoreCommands/SwiftCommandState.swift | 10 +- Sources/PackageGraph/BuildTriple.swift | 6 +- Sources/PackageGraph/ModulesGraph.swift | 64 ++- .../BuildParameters/BuildParameters.swift | 24 +- .../BuildSystem/BuildSystem.swift | 26 +- .../Plugins/PluginInvocation.swift | 8 +- .../SPMTestSupport/MockBuildTestHelper.swift | 122 ++++- .../SPMTestSupport/PackageGraphTester.swift | 29 +- Sources/XCBuildSupport/XcodeBuildSystem.swift | 4 +- Sources/swift-bootstrap/main.swift | 1 + Tests/BuildTests/BuildOperationTests.swift | 27 +- Tests/BuildTests/BuildPlanTests.swift | 424 ++++++++---------- .../ClangTargetBuildDescriptionTests.swift | 1 + .../CrossCompilationBuildPlanTests.swift | 74 ++- .../LLBuildManifestBuilderTests.swift | 93 ++-- .../BuildTests/ModuleAliasingBuildTests.swift | 202 ++++++--- .../ProductBuildDescriptionTests.swift | 2 +- Tests/FunctionalTests/PluginTests.swift | 2 +- .../CrossCompilationPackageGraphTests.swift | 2 +- .../PackageGraphTests/ModulesGraphTests.swift | 6 +- .../PluginInvocationTests.swift | 27 +- .../SourceKitLSPAPITests.swift | 24 +- 43 files changed, 997 insertions(+), 778 deletions(-) diff --git a/Sources/Build/BuildDescription/PluginDescription.swift b/Sources/Build/BuildDescription/PluginDescription.swift index ed6f648ef0c..e7259ec3d45 100644 --- a/Sources/Build/BuildDescription/PluginDescription.swift +++ b/Sources/Build/BuildDescription/PluginDescription.swift @@ -29,6 +29,9 @@ public final class PluginDescription: Codable { /// the plugin). public let targetName: String + /// The language-level target name. + public let targetC99Name: String + /// The names of any plugin products in that package that vend the plugin /// to other packages. public let productNames: [String] @@ -56,6 +59,7 @@ public final class PluginDescription: Codable { self.package = package.identity self.targetName = target.name + self.targetC99Name = target.c99name self.productNames = products.map(\.name) self.toolsVersion = toolsVersion self.sources = target.sources diff --git a/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift b/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift index 59e5e2abacd..7701ea32e28 100644 --- a/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift +++ b/Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift @@ -17,7 +17,7 @@ import SPMBuildCore extension ResolvedModule { func tempsPath(_ buildParameters: BuildParameters) -> AbsolutePath { - let suffix = buildParameters.suffix(triple: self.buildTriple) + let suffix = buildParameters.suffix return buildParameters.buildPath.appending(component: "\(self.c99name)\(suffix).build") } } diff --git a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift index eed9a9ce012..79d11929e5f 100644 --- a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift @@ -44,10 +44,7 @@ public final class SwiftTargetBuildDescription { public let toolsVersion: ToolsVersion /// The build parameters for this target. - let defaultBuildParameters: BuildParameters - - /// The build parameters for build tools. - let toolsBuildParameters: BuildParameters + let buildParameters: BuildParameters /// Path to the temporary directory for this target. let tempsPath: AbsolutePath @@ -66,8 +63,8 @@ public final class SwiftTargetBuildDescription { /// Path to the bundle generated for this module (if any). var bundlePath: AbsolutePath? { if let bundleName = target.underlying.potentialBundleName, needsResourceBundle { - let suffix = self.defaultBuildParameters.suffix(triple: self.target.buildTriple) - return self.defaultBuildParameters.bundlePath(named: bundleName + suffix) + let suffix = self.buildParameters.suffix + return self.buildParameters.bundlePath(named: bundleName + suffix) } else { return nil } @@ -105,7 +102,7 @@ public final class SwiftTargetBuildDescription { let relativeSources = self.target.sources.relativePaths + self.derivedSources.relativePaths + self.pluginDerivedSources.relativePaths - let ltoEnabled = self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode != nil + let ltoEnabled = self.buildParameters.linkingParameters.linkTimeOptimizationMode != nil let objectFileExtension = ltoEnabled ? "bc" : "o" return try relativeSources.map { try AbsolutePath( @@ -116,14 +113,14 @@ public final class SwiftTargetBuildDescription { } var modulesPath: AbsolutePath { - let suffix = self.defaultBuildParameters.suffix(triple: self.target.buildTriple) - return self.defaultBuildParameters.buildPath.appending(component: "Modules\(suffix)") + let suffix = self.buildParameters.suffix + return self.buildParameters.buildPath.appending(component: "Modules\(suffix)") } /// The path to the swiftmodule file after compilation. public var moduleOutputPath: AbsolutePath { // note: needs to be public because of sourcekit-lsp // If we're an executable and we're not allowing test targets to link against us, we hide the module. - let triple = defaultBuildParameters.triple + let triple = buildParameters.triple let allowLinkingAgainstExecutables = (triple.isDarwin() || triple.isLinux() || triple.isWindows()) && self.toolsVersion >= .v5_5 let dirPath = (target.type == .executable && !allowLinkingAgainstExecutables) ? self.tempsPath : self.modulesPath return dirPath.appending(component: "\(self.target.c99name).swiftmodule") @@ -238,7 +235,7 @@ public final class SwiftTargetBuildDescription { public let prebuildCommandResults: [PrebuildCommandResult] /// Any macro products that this target requires to build. - public let requiredMacroProducts: [ResolvedProduct] + public let requiredMacroProducts: [ProductBuildDescription] /// ObservabilityScope with which to emit diagnostics private let observabilityScope: ObservabilityScope @@ -255,11 +252,10 @@ public final class SwiftTargetBuildDescription { target: ResolvedModule, toolsVersion: ToolsVersion, additionalFileRules: [FileRuleDescription] = [], - destinationBuildParameters: BuildParameters, - toolsBuildParameters: BuildParameters, + buildParameters: BuildParameters, buildToolPluginInvocationResults: [BuildToolPluginInvocationResult] = [], prebuildCommandResults: [PrebuildCommandResult] = [], - requiredMacroProducts: [ResolvedProduct] = [], + requiredMacroProducts: [ProductBuildDescription] = [], testTargetRole: TestTargetRole? = nil, shouldGenerateTestObservation: Bool = false, shouldDisableSandbox: Bool, @@ -274,8 +270,7 @@ public final class SwiftTargetBuildDescription { self.package = package self.target = target self.toolsVersion = toolsVersion - self.defaultBuildParameters = destinationBuildParameters - self.toolsBuildParameters = toolsBuildParameters + self.buildParameters = buildParameters // Unless mentioned explicitly, use the target type to determine if this is a test target. if let testTargetRole { @@ -286,7 +281,7 @@ public final class SwiftTargetBuildDescription { self.testTargetRole = nil } - self.tempsPath = target.tempsPath(destinationBuildParameters) + self.tempsPath = target.tempsPath(self.buildParameters) self.derivedSources = Sources(paths: [], root: self.tempsPath.appending("DerivedSources")) self.buildToolPluginInvocationResults = buildToolPluginInvocationResults self.prebuildCommandResults = prebuildCommandResults @@ -300,7 +295,7 @@ public final class SwiftTargetBuildDescription { target: target, toolsVersion: toolsVersion, additionalFileRules: additionalFileRules, - buildParameters: destinationBuildParameters, + buildParameters: self.buildParameters, buildToolPluginInvocationResults: buildToolPluginInvocationResults, prebuildCommandResults: prebuildCommandResults, observabilityScope: observabilityScope @@ -341,13 +336,13 @@ public final class SwiftTargetBuildDescription { } guard - self.defaultBuildParameters.triple.isDarwin() && - self.defaultBuildParameters.testingParameters.experimentalTestOutput + self.buildParameters.triple.isDarwin() && + self.buildParameters.testingParameters.experimentalTestOutput else { return } - let content = generateTestObservationCode(buildParameters: self.defaultBuildParameters) + let content = generateTestObservationCode(buildParameters: self.buildParameters) // FIXME: We should generate this file during the actual build. self.derivedSources.relativePaths.append(subpath) @@ -366,7 +361,7 @@ public final class SwiftTargetBuildDescription { guard let bundlePath else { return } let mainPathSubstitution: String - if self.defaultBuildParameters.triple.isWASI() { + if self.buildParameters.triple.isWASI() { // We prefer compile-time evaluation of the bundle path here for WASI. There's no benefit in evaluating this // at runtime, especially as `Bundle` support in WASI Foundation is partial. We expect all resource paths to // evaluate to `/\(resourceBundleName)/\(resourcePath)`, which allows us to pass this path to JS APIs like @@ -423,15 +418,15 @@ public final class SwiftTargetBuildDescription { #if BUILD_MACROS_AS_DYLIBS self.requiredMacroProducts.forEach { macro in - args += ["-Xfrontend", "-load-plugin-library", "-Xfrontend", self.toolsBuildParameters.binaryPath(for: macro).pathString] + args += ["-Xfrontend", "-load-plugin-library", "-Xfrontend", macro.binaryPath.pathString] } #else try self.requiredMacroProducts.forEach { macro in - if let macroTarget = macro.targets.first { - let executablePath = try self.toolsBuildParameters.binaryPath(for: macro).pathString + if let macroTarget = macro.product.targets.first { + let executablePath = try macro.binaryPath.pathString args += ["-Xfrontend", "-load-plugin-executable", "-Xfrontend", "\(executablePath)#\(macroTarget.c99name)"] } else { - throw InternalError("macro product \(macro.name) has no targets") // earlier validation should normally catch this + throw InternalError("macro product \(macro.product.name) has no targets") // earlier validation should normally catch this } } #endif @@ -439,7 +434,7 @@ public final class SwiftTargetBuildDescription { if self.shouldDisableSandbox { let toolchainSupportsDisablingSandbox = DriverSupport.checkSupportedFrontendFlags( flags: ["-disable-sandbox"], - toolchain: self.defaultBuildParameters.toolchain, + toolchain: self.buildParameters.toolchain, fileSystem: fileSystem ) if toolchainSupportsDisablingSandbox { @@ -458,10 +453,10 @@ public final class SwiftTargetBuildDescription { /// The arguments needed to compile this target. public func compileArguments() throws -> [String] { var args = [String]() - args += try self.defaultBuildParameters.tripleArgs(for: self.target) + args += try self.buildParameters.tripleArgs(for: self.target) // pass `-v` during verbose builds. - if self.defaultBuildParameters.outputParameters.isVerbose { + if self.buildParameters.outputParameters.isVerbose { args += ["-v"] } @@ -469,22 +464,22 @@ public final class SwiftTargetBuildDescription { // // Technically, it should be enabled whenever WMO is off but we // don't currently make that distinction in SwiftPM - switch self.defaultBuildParameters.configuration { + switch self.buildParameters.configuration { case .debug: args += ["-enable-batch-mode"] case .release: break } - args += self.defaultBuildParameters.indexStoreArguments(for: self.target) + args += self.buildParameters.indexStoreArguments(for: self.target) args += self.optimizationArguments args += self.testingArguments - args += ["-j\(self.defaultBuildParameters.workers)"] + args += ["-j\(self.buildParameters.workers)"] args += self.activeCompilationConditions args += self.additionalFlags args += try self.moduleCacheArgs args += self.stdlibArguments - args += self.defaultBuildParameters.sanitizers.compileSwiftFlags() + args += self.buildParameters.sanitizers.compileSwiftFlags() args += ["-parseable-output"] // If we're compiling the main module of an executable other than the one that @@ -504,8 +499,8 @@ public final class SwiftTargetBuildDescription { // we can rename the symbol unconditionally. // No `-` for these flags because the set of Strings in driver.supportedFrontendFlags do // not have a leading `-` - if self.defaultBuildParameters.driverParameters.canRenameEntrypointFunctionName, - self.defaultBuildParameters.linkerFlagsForRenamingMainFunction(of: self.target) != nil + if self.buildParameters.driverParameters.canRenameEntrypointFunctionName, + self.buildParameters.linkerFlagsForRenamingMainFunction(of: self.target) != nil { args += ["-Xfrontend", "-entry-point-function-name", "-Xfrontend", "\(self.target.c99name)_main"] } @@ -518,7 +513,7 @@ public final class SwiftTargetBuildDescription { // Only add the build path to the framework search path if there are binary frameworks to link against. if !self.libraryBinaryPaths.isEmpty { - args += ["-F", self.defaultBuildParameters.buildPath.pathString] + args += ["-F", self.buildParameters.buildPath.pathString] } // Emit the ObjC compatibility header if enabled. @@ -527,12 +522,12 @@ public final class SwiftTargetBuildDescription { } // Add arguments needed for code coverage if it is enabled. - if self.defaultBuildParameters.testingParameters.enableCodeCoverage { + if self.buildParameters.testingParameters.enableCodeCoverage { args += ["-profile-coverage-mapping", "-profile-generate"] } // Add arguments to colorize output if stdout is tty - if self.defaultBuildParameters.outputParameters.isColorized { + if self.buildParameters.outputParameters.isColorized { args += ["-color-diagnostics"] } @@ -542,7 +537,7 @@ public final class SwiftTargetBuildDescription { switch testTargetRole { case .discovery, .entryPoint: for dependency in try self.target.recursiveTargetDependencies() { - let dependencyScope = self.defaultBuildParameters.createScope(for: dependency) + let dependencyScope = self.buildParameters.createScope(for: dependency) let dependencySwiftFlags = dependencyScope.evaluate(.OTHER_SWIFT_FLAGS) if let interopModeFlag = dependencySwiftFlags.first(where: { $0.hasPrefix("-cxx-interoperability-mode=") }) { args += [interopModeFlag] @@ -562,17 +557,17 @@ public final class SwiftTargetBuildDescription { // Add the output for the `.swiftinterface`, if requested or if library evolution has been enabled some other // way. - if self.defaultBuildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") { + if self.buildParameters.driverParameters.enableParseableModuleInterfaces || args.contains("-enable-library-evolution") { args += ["-emit-module-interface-path", self.parseableModuleInterfaceOutputPath.pathString] } - args += self.defaultBuildParameters.toolchain.extraFlags.swiftCompilerFlags + args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags // User arguments (from -Xswiftc) should follow generated arguments to allow user overrides - args += self.defaultBuildParameters.flags.swiftCompilerFlags + args += self.buildParameters.flags.swiftCompilerFlags - args += self.defaultBuildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags() + args += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags() // User arguments (from -Xcc) should follow generated arguments to allow user overrides - args += self.defaultBuildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags() + args += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags() // TODO: Pass -Xcxx flags to swiftc (#6491) // Uncomment when downstream support arrives. @@ -581,7 +576,7 @@ public final class SwiftTargetBuildDescription { // args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags() // Enable the correct LTO mode if requested. - switch self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode { + switch self.buildParameters.linkingParameters.linkTimeOptimizationMode { case nil: break case .full: @@ -591,7 +586,7 @@ public final class SwiftTargetBuildDescription { } // Pass default include paths from the toolchain. - for includeSearchPath in self.defaultBuildParameters.toolchain.includeSearchPaths { + for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths { args += ["-I", includeSearchPath.pathString] } @@ -616,14 +611,14 @@ public final class SwiftTargetBuildDescription { args += self.package.packageNameArgument( target: self.target, - isPackageNameSupported: self.defaultBuildParameters.driverParameters.isPackageAccessModifierSupported + isPackageNameSupported: self.buildParameters.driverParameters.isPackageAccessModifierSupported ) args += try self.macroArguments() // rdar://117578677 // Pass -fno-omit-frame-pointer to support backtraces // this can be removed once the backtracer uses DWARF instead of frame pointers - if let omitFramePointers = self.defaultBuildParameters.debuggingParameters.omitFramePointers { + if let omitFramePointers = self.buildParameters.debuggingParameters.omitFramePointers { if omitFramePointers { args += ["-Xcc", "-fomit-frame-pointer"] } else { @@ -638,14 +633,14 @@ public final class SwiftTargetBuildDescription { /// such as emitting a module or supplementary outputs. public func emitCommandLine(scanInvocation: Bool = false) throws -> [String] { var result: [String] = [] - result.append(self.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) + result.append(self.buildParameters.toolchain.swiftCompilerPath.pathString) result.append("-module-name") result.append(self.target.c99name) result.append( contentsOf: self.package.packageNameArgument( target: self.target, - isPackageNameSupported: self.defaultBuildParameters.driverParameters.isPackageAccessModifierSupported + isPackageNameSupported: self.buildParameters.driverParameters.isPackageAccessModifierSupported ) ) if !scanInvocation { @@ -661,7 +656,7 @@ public final class SwiftTargetBuildDescription { result.append(try self.writeOutputFileMap().pathString) } - if self.defaultBuildParameters.useWholeModuleOptimization { + if self.buildParameters.useWholeModuleOptimization { result.append("-whole-module-optimization") result.append("-num-threads") result.append(String(ProcessInfo.processInfo.activeProcessorCount)) @@ -681,7 +676,7 @@ public final class SwiftTargetBuildDescription { /// Returns true if ObjC compatibility header should be emitted. private var shouldEmitObjCCompatibilityHeader: Bool { - self.defaultBuildParameters.triple.isDarwin() && self.target.type == .library + self.buildParameters.triple.isDarwin() && self.target.type == .library } func writeOutputFileMap() throws -> AbsolutePath { @@ -695,7 +690,7 @@ public final class SwiftTargetBuildDescription { """# - if self.defaultBuildParameters.useWholeModuleOptimization { + if self.buildParameters.useWholeModuleOptimization { let moduleName = self.target.c99name content += #""" @@ -726,7 +721,7 @@ public final class SwiftTargetBuildDescription { // Write out the entries for each source file. let sources = self.sources let objects = try self.objects - let ltoEnabled = self.defaultBuildParameters.linkingParameters.linkTimeOptimizationMode != nil + let ltoEnabled = self.buildParameters.linkingParameters.linkTimeOptimizationMode != nil let objectKey = ltoEnabled ? "llvm-bc" : "object" for idx in 0.. [String] { - let scope = self.defaultBuildParameters.createScope(for: self.target) + let scope = self.buildParameters.createScope(for: self.target) var flags: [String] = [] // A custom swift version. @@ -844,7 +839,7 @@ public final class SwiftTargetBuildDescription { private var activeCompilationConditions: [String] { var compilationConditions = ["-DSWIFT_PACKAGE"] - switch self.defaultBuildParameters.configuration { + switch self.buildParameters.configuration { case .debug: compilationConditions += ["-DDEBUG"] case .release: @@ -856,7 +851,7 @@ public final class SwiftTargetBuildDescription { /// Optimization arguments according to the build configuration. private var optimizationArguments: [String] { - switch self.defaultBuildParameters.configuration { + switch self.buildParameters.configuration { case .debug: return ["-Onone"] case .release: @@ -870,7 +865,7 @@ public final class SwiftTargetBuildDescription { // test targets must be built with -enable-testing // since its required for test discovery (the non objective-c reflection kind) return ["-enable-testing"] - } else if self.defaultBuildParameters.testingParameters.enableTestability { + } else if self.buildParameters.testingParameters.enableTestability { return ["-enable-testing"] } else { return [] @@ -880,20 +875,20 @@ public final class SwiftTargetBuildDescription { /// Module cache arguments. private var moduleCacheArgs: [String] { get throws { - ["-module-cache-path", try self.defaultBuildParameters.moduleCache.pathString] + ["-module-cache-path", try self.buildParameters.moduleCache.pathString] } } private var stdlibArguments: [String] { var arguments: [String] = [] - let isLinkingStaticStdlib = self.defaultBuildParameters.linkingParameters.shouldLinkStaticSwiftStdlib - && self.defaultBuildParameters.triple.isSupportingStaticStdlib + let isLinkingStaticStdlib = self.buildParameters.linkingParameters.shouldLinkStaticSwiftStdlib + && self.buildParameters.triple.isSupportingStaticStdlib if isLinkingStaticStdlib { arguments += ["-static-stdlib"] } - if let resourcesPath = self.defaultBuildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) { + if let resourcesPath = self.buildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) { arguments += ["-resource-dir", "\(resourcesPath)"] } diff --git a/Sources/Build/BuildDescription/TargetBuildDescription.swift b/Sources/Build/BuildDescription/TargetBuildDescription.swift index 3c6ace54221..4ddda8dec70 100644 --- a/Sources/Build/BuildDescription/TargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/TargetBuildDescription.swift @@ -101,7 +101,7 @@ public enum TargetBuildDescription { var buildParameters: BuildParameters { switch self { case .swift(let swiftTargetBuildDescription): - return swiftTargetBuildDescription.defaultBuildParameters + return swiftTargetBuildDescription.buildParameters case .clang(let clangTargetBuildDescription): return clangTargetBuildDescription.buildParameters } diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift index e6ddfc1a4fb..3f23cf1cbc3 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift @@ -93,7 +93,7 @@ extension LLBuildManifestBuilder { let additionalInputs = try addBuildToolPlugins(.clang(target)) // Create a phony node to represent the entire target. - let targetName = target.target.getLLBuildTargetName(buildParameters: target.buildParameters) + let targetName = target.llbuildTargetName let output: Node = .virtual(targetName) self.manifest.addNode(output, toTarget: targetName) diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift index cf8a797ed9c..d95e5b46662 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift @@ -11,11 +11,14 @@ //===----------------------------------------------------------------------===// import struct Basics.AbsolutePath +import struct Basics.InternalError import struct LLBuildManifest.Node +import struct SPMBuildCore.BuildParameters +import struct PackageGraph.ResolvedProduct extension LLBuildManifestBuilder { func createProductCommand(_ buildProduct: ProductBuildDescription) throws { - let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters) + let cmdName = try buildProduct.commandName // Add dependency on Info.plist generation on Darwin platforms. let testInputs: [AbsolutePath] @@ -34,7 +37,7 @@ extension LLBuildManifestBuilder { } // Create a phony node to represent the entire target. - let targetName = try buildProduct.product.getLLBuildTargetName(buildParameters: buildProduct.buildParameters) + let targetName = try buildProduct.llbuildTargetName let output: Node = .virtual(targetName) let finalProductNode: Node @@ -85,7 +88,7 @@ extension LLBuildManifestBuilder { outputPath: plistPath ) - let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters) + let cmdName = try buildProduct.commandName let codeSigningOutput = Node.virtual(targetName + "-CodeSigning") try self.manifest.addShellCmd( name: "\(cmdName)-entitlements", @@ -120,3 +123,48 @@ extension LLBuildManifestBuilder { ) } } + +extension ProductBuildDescription { + package var llbuildTargetName: String { + get throws { + try self.product.getLLBuildTargetName(buildParameters: self.buildParameters) + } + } + + package var commandName: String { + get throws { + try "C.\(self.llbuildTargetName)\(self.buildParameters.suffix)" + } + } +} + +extension ResolvedProduct { + public func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String { + let triple = buildParameters.triple.tripleString + let config = buildParameters.buildConfig + let suffix = buildParameters.suffix + let potentialExecutableTargetName = "\(name)-\(triple)-\(config)\(suffix).exe" + let potentialLibraryTargetName = "\(name)-\(triple)-\(config)\(suffix).dylib" + + switch type { + case .library(.dynamic): + return potentialLibraryTargetName + case .test: + return "\(name)-\(triple)-\(config)\(suffix).test" + case .library(.static): + return "\(name)-\(triple)-\(config)\(suffix).a" + case .library(.automatic): + throw InternalError("automatic library not supported") + case .executable, .snippet: + return potentialExecutableTargetName + case .macro: + #if BUILD_MACROS_AS_DYLIBS + return potentialLibraryTargetName + #else + return potentialExecutableTargetName + #endif + case .plugin: + throw InternalError("unexpectedly asked for the llbuild target name of a plugin product") + } + } +} diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift index df561d46b8b..79917f4eb43 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift @@ -45,7 +45,7 @@ extension LLBuildManifestBuilder { outputs.append(output) } - let cmdName = target.target.getLLBuildResourcesCmdName(buildParameters: target.buildParameters) + let cmdName = target.llbuildResourcesCmdName self.manifest.addPhonyCmd(name: cmdName, inputs: outputs, outputs: [.virtual(cmdName)]) return .virtual(cmdName) diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift index a2cf42bf2fb..bf113cf6f81 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift @@ -45,7 +45,7 @@ extension LLBuildManifestBuilder { let moduleNode = Node.file(target.moduleOutputPath) let cmdOutputs = objectNodes + [moduleNode] - if target.defaultBuildParameters.driverParameters.useIntegratedSwiftDriver { + if target.buildParameters.driverParameters.useIntegratedSwiftDriver { try self.addSwiftCmdsViaIntegratedDriver( target, inputs: inputs, @@ -68,7 +68,7 @@ extension LLBuildManifestBuilder { // jobs needed to build this Swift target. var commandLine = try target.emitCommandLine() commandLine.append("-driver-use-frontend-path") - commandLine.append(target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) + commandLine.append(target.buildParameters.toolchain.swiftCompilerPath.pathString) // FIXME: At some point SwiftPM should provide its own executor for // running jobs/launching processes during planning let resolver = try ArgsResolver(fileSystem: target.fileSystem) @@ -132,7 +132,7 @@ extension LLBuildManifestBuilder { // common intermediate dependency modules, such dependencies can lead // to cycles in the resulting manifest. var manifestNodeInputs: [Node] = [] - if targetDescription.defaultBuildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) { + if targetDescription.buildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) { manifestNodeInputs = jobInputs } else { manifestNodeInputs = (inputs + jobInputs).uniqued() @@ -191,11 +191,8 @@ extension LLBuildManifestBuilder { public func addTargetsToExplicitBuildManifest() throws { // Sort the product targets in topological order in order to collect and "bubble up" // their respective dependency graphs to the depending targets. - let nodes: [ResolvedModule.Dependency] = try self.plan.targetMap.keys.compactMap { - guard let target = self.plan.graph.allTargets[$0] else { - throw InternalError("unknown target \($0)") - } - return ResolvedModule.Dependency.target(target, conditions: []) + let nodes = self.plan.targets.compactMap { + ResolvedModule.Dependency.target($0.target, conditions: []) } let allPackageDependencies = try topologicalSort(nodes, successors: { $0.dependencies }) // Instantiate the inter-module dependency oracle which will cache commonly-scanned @@ -287,7 +284,7 @@ extension LLBuildManifestBuilder { // jobs needed to build this Swift target. var commandLine = try targetDescription.emitCommandLine() commandLine.append("-driver-use-frontend-path") - commandLine.append(targetDescription.defaultBuildParameters.toolchain.swiftCompilerPath.pathString) + commandLine.append(targetDescription.buildParameters.toolchain.swiftCompilerPath.pathString) commandLine.append("-experimental-explicit-module-build") let resolver = try ArgsResolver(fileSystem: self.fileSystem) let executor = SPMSwiftDriverExecutor( @@ -378,14 +375,14 @@ extension LLBuildManifestBuilder { cmdOutputs: [Node] ) throws { let isLibrary = target.target.type == .library || target.target.type == .test - let cmdName = target.target.getCommandName(buildParameters: target.defaultBuildParameters) + let cmdName = target.getCommandName() self.manifest.addWriteSourcesFileListCommand(sources: target.sources, sourcesFileListPath: target.sourcesFileListPath) self.manifest.addSwiftCmd( name: cmdName, inputs: inputs + [Node.file(target.sourcesFileListPath)], outputs: cmdOutputs, - executable: target.defaultBuildParameters.toolchain.swiftCompilerPath, + executable: target.buildParameters.toolchain.swiftCompilerPath, moduleName: target.target.c99name, moduleAliases: target.target.moduleAliases, moduleOutputPath: target.moduleOutputPath, @@ -396,7 +393,7 @@ extension LLBuildManifestBuilder { sources: target.sources, fileList: target.sourcesFileListPath, isLibrary: isLibrary, - wholeModuleOptimization: target.defaultBuildParameters.configuration == .release, + wholeModuleOptimization: target.buildParameters.configuration == .release, outputFileMapPath: try target.writeOutputFileMap() // FIXME: Eliminate side effect. ) } @@ -406,7 +403,7 @@ extension LLBuildManifestBuilder { ) throws -> [Node] { var inputs = target.sources.map(Node.file) - let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.defaultBuildParameters) + let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.buildParameters) inputs.append(.file(swiftVersionFilePath)) // Add resources node as the input to the target. This isn't great because we @@ -433,14 +430,10 @@ extension LLBuildManifestBuilder { // Depend on the binary for executable targets. if target.type == .executable { // FIXME: Optimize. - let product = try plan.graph.allProducts.first { - try $0.type == .executable && $0.executableTarget.id == target.id - } - if let product { - guard let planProduct = plan.productMap[product.id] else { - throw InternalError("unknown product \(product)") - } - try inputs.append(file: planProduct.binaryPath) + if let productDescription = try plan.productMap.values.first(where: { + try $0.product.type == .executable && $0.product.executableTarget.id == target.id + }) { + try inputs.append(file: productDescription.binaryPath) } return } @@ -457,7 +450,7 @@ extension LLBuildManifestBuilder { } } - for dependency in target.target.dependencies(satisfying: target.defaultBuildParameters.buildEnvironment) { + for dependency in target.target.dependencies(satisfying: target.buildParameters.buildEnvironment) { switch dependency { case .target(let target, _): try addStaticTargetInputs(target) @@ -484,7 +477,7 @@ extension LLBuildManifestBuilder { } for binaryPath in target.libraryBinaryPaths { - let path = target.defaultBuildParameters.destinationPath(forBinaryAt: binaryPath) + let path = target.buildParameters.destinationPath(forBinaryAt: binaryPath) if self.fileSystem.isDirectory(binaryPath) { inputs.append(directory: path) } else { @@ -496,7 +489,7 @@ extension LLBuildManifestBuilder { // Depend on any required macro product's output. try target.requiredMacroProducts.forEach { macro in - try inputs.append(.virtual(macro.getLLBuildTargetName(buildParameters: target.defaultBuildParameters))) + try inputs.append(.virtual(macro.llbuildTargetName)) } return inputs + additionalInputs @@ -505,7 +498,7 @@ extension LLBuildManifestBuilder { /// 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(buildParameters: target.defaultBuildParameters) + let targetName = target.getLLBuildTargetName() let targetOutput: Node = .virtual(targetName) self.manifest.addNode(targetOutput, toTarget: targetName) @@ -514,7 +507,7 @@ extension LLBuildManifestBuilder { inputs: cmdOutputs, outputs: [targetOutput] ) - if self.plan.graph.isInRootPackages(target.target, satisfying: target.defaultBuildParameters.buildEnvironment) { + if self.plan.graph.isInRootPackages(target.target, satisfying: target.buildParameters.buildEnvironment) { if !target.isTestTarget { self.addNode(targetOutput, toTarget: .main) } @@ -524,13 +517,13 @@ extension LLBuildManifestBuilder { private func addModuleWrapCmd(_ target: SwiftTargetBuildDescription) throws { // Add commands to perform the module wrapping Swift modules when debugging strategy is `modulewrap`. - guard target.defaultBuildParameters.debuggingStrategy == .modulewrap else { return } + guard target.buildParameters.debuggingStrategy == .modulewrap else { return } var moduleWrapArgs = [ - target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString, + target.buildParameters.toolchain.swiftCompilerPath.pathString, "-modulewrap", target.moduleOutputPath.pathString, "-o", target.wrappedModuleOutputPath.pathString, ] - moduleWrapArgs += try target.defaultBuildParameters.tripleArgs(for: target.target) + moduleWrapArgs += try target.buildParameters.tripleArgs(for: target.target) self.manifest.addShellCmd( name: target.wrappedModuleOutputPath.pathString, description: "Wrapping AST for \(target.target.name) for debugging", @@ -611,3 +604,13 @@ extension Driver { } } } + +extension SwiftTargetBuildDescription { + public func getCommandName() -> String { + "C." + self.getLLBuildTargetName() + } + + public func getLLBuildTargetName() -> String { + self.target.getLLBuildTargetName(buildParameters: self.buildParameters) + } +} diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift index d1bf1f5f7c3..61f8ee4c805 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -316,52 +316,21 @@ extension TargetBuildDescription { } } -extension ResolvedModule { - public func getCommandName(buildParameters: BuildParameters) -> String { - "C." + self.getLLBuildTargetName(buildParameters: buildParameters) - } - - public func getLLBuildTargetName(buildParameters: BuildParameters) -> String { - "\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module" - } - - public func getLLBuildResourcesCmdName(buildParameters: BuildParameters) -> String { - "\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module-resources" +extension TargetBuildDescription { + package var llbuildResourcesCmdName: String { + "\(self.target.name)-\(self.buildParameters.triple.tripleString)-\(self.buildParameters.buildConfig)\(self.buildParameters.suffix).module-resources" } } -extension ResolvedProduct { - public func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String { - let triple = buildParameters.triple.tripleString - let config = buildParameters.buildConfig - let suffix = buildParameters.suffix(triple: self.buildTriple) - let potentialExecutableTargetName = "\(name)-\(triple)-\(config)\(suffix).exe" - let potentialLibraryTargetName = "\(name)-\(triple)-\(config)\(suffix).dylib" - - switch type { - case .library(.dynamic): - return potentialLibraryTargetName - case .test: - return "\(name)-\(triple)-\(config)\(suffix).test" - case .library(.static): - return "\(name)-\(triple)-\(config)\(suffix).a" - case .library(.automatic): - throw InternalError("automatic library not supported") - case .executable, .snippet: - return potentialExecutableTargetName - case .macro: - #if BUILD_MACROS_AS_DYLIBS - return potentialLibraryTargetName - #else - return potentialExecutableTargetName - #endif - case .plugin: - throw InternalError("unexpectedly asked for the llbuild target name of a plugin product") - } +extension ClangTargetBuildDescription { + package var llbuildTargetName: String { + self.target.getLLBuildTargetName(buildParameters: self.buildParameters) } +} - public func getCommandName(buildParameters: BuildParameters) throws -> String { - try "C.\(self.getLLBuildTargetName(buildParameters: buildParameters))\(buildParameters.suffix(triple: self.buildTriple))" +extension ResolvedModule { + public func getLLBuildTargetName(buildParameters: BuildParameters) -> String { + "\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix).module" } } diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 97d43ba2ea1..efa084748bd 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -378,9 +378,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS let subsetDescriptor: String? switch subset { - case .product(let productName): + case .product(let productName, _): subsetDescriptor = "product '\(productName)'" - case .target(let targetName): + case .target(let targetName, _): subsetDescriptor = "target: '\(targetName)'" case .allExcludingTests, .allIncludingTests: subsetDescriptor = nil @@ -433,10 +433,10 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS case .allExcludingTests, .allIncludingTests: pluginsToCompile = allPlugins continueBuilding = true - case .product(let productName): + case .product(let productName, _): pluginsToCompile = allPlugins.filter{ $0.productNames.contains(productName) } continueBuilding = pluginsToCompile.isEmpty - case .target(let targetName): + case .target(let targetName, _): pluginsToCompile = allPlugins.filter{ $0.targetName == targetName } continueBuilding = pluginsToCompile.isEmpty } @@ -522,17 +522,79 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS return LLBuildManifestBuilder.TargetKind.main.targetName case .allIncludingTests: return LLBuildManifestBuilder.TargetKind.test.targetName - default: + case .product(let productName, let destination): // FIXME: This is super unfortunate that we might need to load the package graph. let graph = try getPackageGraph() - if let result = subset.llbuildTargetName( - for: graph, - buildParameters: self.productsBuildParameters, - observabilityScope: self.observabilityScope - ) { - return result + + var product = graph.product( + for: productName, + destination: destination == .host ? .tools : .destination + ) + + var buildParameters = if destination == .host { + self.toolsBuildParameters + } else { + self.productsBuildParameters } - throw Diagnostics.fatalError + + // It's possible to request a build of a macro or a plugin via `swift build` + // which won't have the right destination set because it's impossible to indicate it. + if product == nil && destination == .target { + if let toolsProduct = graph.product(for: productName, destination: .tools), + toolsProduct.type == .macro || toolsProduct.type == .plugin + { + product = toolsProduct + buildParameters = self.toolsBuildParameters + } + } + + guard let product else { + observabilityScope.emit(error: "no product named '\(productName)'") + throw Diagnostics.fatalError + } + + // If the product is automatic, we build the main target because automatic products + // do not produce a binary right now. + if product.type == .library(.automatic) { + observabilityScope.emit( + warning: + "'--product' cannot be used with the automatic product '\(productName)'; building the default target instead" + ) + return LLBuildManifestBuilder.TargetKind.main.targetName + } + return try product.getLLBuildTargetName(buildParameters: buildParameters) + case .target(let targetName, let destination): + // FIXME: This is super unfortunate that we might need to load the package graph. + let graph = try getPackageGraph() + + var target = graph.target( + for: targetName, + destination: destination == .host ? .tools : .destination + ) + + var buildParameters = if destination == .host { + self.toolsBuildParameters + } else { + self.productsBuildParameters + } + + // It's possible to request a build of a macro or a plugin via `swift build` + // which won't have the right destination because it's impossible to indicate it. + if target == nil && destination == .target { + if let toolsTarget = graph.target(for: targetName, destination: .tools), + toolsTarget.type == .macro || toolsTarget.type == .plugin + { + target = toolsTarget + buildParameters = self.toolsBuildParameters + } + } + + guard let target else { + observabilityScope.emit(error: "no target named '\(targetName)'") + throw Diagnostics.fatalError + } + + return target.getLLBuildTargetName(buildParameters: buildParameters) } } @@ -550,15 +612,15 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // done, which makes it hard to realign them all at once. var pluginsBuildParameters = self.toolsBuildParameters pluginsBuildParameters.dataPath = pluginsBuildParameters.dataPath.parentDirectory.appending(components: ["plugins", "tools"]) - var buildToolsGraph = graph - try buildToolsGraph.updateBuildTripleRecursively(.tools) + + var targetBuildParameters = pluginsBuildParameters + targetBuildParameters.destination = .target let buildOperationForPluginDependencies = BuildOperation( - // FIXME: this doesn't maintain the products/tools split cleanly - productsBuildParameters: pluginsBuildParameters, + productsBuildParameters: targetBuildParameters, toolsBuildParameters: pluginsBuildParameters, cacheBuildManifest: false, - packageGraphLoader: { buildToolsGraph }, + packageGraphLoader: { graph }, scratchDirectory: pluginsBuildParameters.dataPath, additionalFileRules: self.additionalFileRules, pkgConfigDirectories: self.pkgConfigDirectories, @@ -569,7 +631,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS fileSystem: self.fileSystem, observabilityScope: self.observabilityScope ) - buildToolPluginInvocationResults = try buildToolsGraph.invokeBuildToolPlugins( + + buildToolPluginInvocationResults = try graph.invokeBuildToolPlugins( outputDir: pluginConfiguration.workDirectory.appending("outputs"), buildParameters: pluginsBuildParameters, additionalFileRules: self.additionalFileRules, @@ -579,8 +642,10 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS observabilityScope: self.observabilityScope, fileSystem: self.fileSystem ) { name, path in - try buildOperationForPluginDependencies.build(subset: .product(name)) - if let builtTool = try buildOperationForPluginDependencies.buildPlan.buildProducts.first(where: { $0.product.name == name}) { + try buildOperationForPluginDependencies.build(subset: .product(name, for: .host)) + if let builtTool = try buildOperationForPluginDependencies.buildPlan.buildProducts.first(where: { + $0.product.name == name && $0.buildParameters.destination == .host + }) { return try builtTool.binaryPath } else { return nil @@ -893,57 +958,26 @@ extension BuildSubset { return Array(graph.reachableTargets) case .allExcludingTests: return graph.reachableTargets.filter { $0.type != .test } - case .product(let productName): - guard let product = graph.allProducts.first(where: { $0.name == productName }) else { + case .product(let productName, let destination): + guard let product = graph.product( + for: productName, + destination: destination == .host ? .tools : .destination + ) else { observabilityScope.emit(error: "no product named '\(productName)'") return nil } return try product.recursiveTargetDependencies() - case .target(let targetName): - guard let target = graph.allTargets.first(where: { $0.name == targetName }) else { + case .target(let targetName, let destination): + guard let target = graph.target( + for: targetName, + destination: destination == .host ? .tools : .destination + ) else { observabilityScope.emit(error: "no target named '\(targetName)'") return nil } return try target.recursiveTargetDependencies() } } - - /// Returns the name of the llbuild target that corresponds to the build subset. - func llbuildTargetName( - for graph: ModulesGraph, - buildParameters: BuildParameters, - observabilityScope: ObservabilityScope - ) -> String? { - switch self { - case .allExcludingTests: - return LLBuildManifestBuilder.TargetKind.main.targetName - case .allIncludingTests: - return LLBuildManifestBuilder.TargetKind.test.targetName - case .product(let productName): - guard let product = graph.allProducts.first(where: { $0.name == productName }) else { - observabilityScope.emit(error: "no product named '\(productName)'") - return nil - } - // If the product is automatic, we build the main target because automatic products - // do not produce a binary right now. - if product.type == .library(.automatic) { - observabilityScope.emit( - warning: - "'--product' cannot be used with the automatic product '\(productName)'; building the default target instead" - ) - return LLBuildManifestBuilder.TargetKind.main.targetName - } - return observabilityScope.trap { - try product.getLLBuildTargetName(buildParameters: buildParameters) - } - case .target(let targetName): - guard let target = graph.allTargets.first(where: { $0.name == targetName }) else { - observabilityScope.emit(error: "no target named '\(targetName)'") - return nil - } - return target.getLLBuildTargetName(buildParameters: buildParameters) - } - } } extension Basics.Diagnostic.Severity { diff --git a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift index 74080c912f0..40944f43f30 100644 --- a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift +++ b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift @@ -386,29 +386,29 @@ public struct BuildDescription: Codable { .explicitTargetDependencyImportCheckingMode self.targetDependencyMap = try plan.targets.reduce(into: [TargetName: [TargetName]]()) { partial, targetBuildDescription in let deps = try targetBuildDescription.target.recursiveDependencies( - satisfying: plan.buildParameters(for: targetBuildDescription.target).buildEnvironment + satisfying: targetBuildDescription.buildParameters.buildEnvironment ) .compactMap(\.target).map(\.c99name) partial[targetBuildDescription.target.c99name] = deps } var targetCommandLines: [TargetName: [CommandLineFlag]] = [:] var generatedSourceTargets: [TargetName] = [] - for (targetID, description) in plan.targetMap { - guard case .swift(let desc) = description, let target = plan.graph.allTargets[targetID] else { + for description in plan.targets { + guard case .swift(let desc) = description else { continue } - let buildParameters = plan.buildParameters(for: target) - targetCommandLines[target.c99name] = + let buildParameters = description.buildParameters + targetCommandLines[desc.target.c99name] = try desc.emitCommandLine(scanInvocation: true) + [ "-driver-use-frontend-path", buildParameters.toolchain.swiftCompilerPath.pathString ] if case .discovery = desc.testTargetRole { - generatedSourceTargets.append(target.c99name) + generatedSourceTargets.append(desc.target.c99name) } } generatedSourceTargets.append( - contentsOf: plan.graph.allTargets.filter { $0.type == .plugin } - .map(\.c99name) + contentsOf: plan.pluginDescriptions + .map(\.targetC99Name) ) self.swiftTargetScanArgs = targetCommandLines self.generatedSourceTargetSet = Set(generatedSourceTargets) diff --git a/Sources/Build/BuildPlan/BuildPlan+Swift.swift b/Sources/Build/BuildPlan/BuildPlan+Swift.swift index 058631598f2..36b1cacde0c 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Swift.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Swift.swift @@ -19,7 +19,7 @@ extension BuildPlan { func plan(swiftTarget: SwiftTargetBuildDescription) throws { // We need to iterate recursive dependencies because Swift compiler needs to see all the targets a target // depends on. - let environment = swiftTarget.defaultBuildParameters.buildEnvironment + let environment = swiftTarget.buildParameters.buildEnvironment for case .target(let dependency, _) in try swiftTarget.target.recursiveDependencies(satisfying: environment) { switch dependency.underlying { case let underlyingTarget as ClangTarget where underlyingTarget.type == .library: @@ -40,7 +40,7 @@ extension BuildPlan { swiftTarget.additionalFlags += try pkgConfig(for: target).cFlags case let target as BinaryTarget: if case .xcframework = target.kind { - let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.defaultBuildParameters.triple) + let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.buildParameters.triple) for library in libraries { library.headersPaths.forEach { swiftTarget.additionalFlags += ["-I", $0.pathString, "-Xcc", "-I", "-Xcc", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan+Test.swift b/Sources/Build/BuildPlan/BuildPlan+Test.swift index b82828608f1..33b4cc140d6 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Test.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Test.swift @@ -16,6 +16,7 @@ import struct Basics.AbsolutePath import struct LLBuildManifest.TestDiscoveryTool import struct LLBuildManifest.TestEntryPointTool import struct PackageGraph.ModulesGraph +import struct PackageGraph.ResolvedPackage import struct PackageGraph.ResolvedProduct import struct PackageGraph.ResolvedModule import struct PackageModel.Sources @@ -26,9 +27,9 @@ import protocol TSCBasic.FileSystem extension BuildPlan { static func makeDerivedTestTargets( + testProducts: [(product: ResolvedProduct, buildDescription: ProductBuildDescription)], destinationBuildParameters: BuildParameters, toolsBuildParameters: BuildParameters, - _ graph: ModulesGraph, shouldDisableSandbox: Bool, _ fileSystem: FileSystem, _ observabilityScope: ObservabilityScope @@ -44,15 +45,14 @@ extension BuildPlan { var isDiscoveryEnabledRedundantly = explicitlyEnabledDiscovery && !isEntryPointPathSpecifiedExplicitly var result: [(ResolvedProduct, SwiftTargetBuildDescription?, SwiftTargetBuildDescription)] = [] - for testProduct in graph.allProducts where testProduct.type == .test { - guard let package = graph.package(for: testProduct) else { - throw InternalError("package not found for \(testProduct)") - } + for (testProduct, testBuildDescription) in testProducts { + let package = testBuildDescription.package + isDiscoveryEnabledRedundantly = isDiscoveryEnabledRedundantly && nil == testProduct.testEntryPointTarget // If a non-explicitly specified test entry point file exists, prefer that over test discovery. // This is designed as an escape hatch when test discovery is not appropriate and for backwards // compatibility for projects that have existing test entry point files (e.g. XCTMain.swift, LinuxMain.swift). - let toolsVersion = graph.package(for: testProduct)?.manifest.toolsVersion ?? .v5_5 + let toolsVersion = package.manifest.toolsVersion // If `testProduct.testEntryPointTarget` is non-nil, it may either represent an `XCTMain.swift` (formerly `LinuxMain.swift`) file // if such a file is located in the package, or it may represent a test entry point file at a path specified by the option @@ -93,21 +93,13 @@ extension BuildPlan { supportedPlatforms: testProduct.supportedPlatforms, platformVersionProvider: testProduct.platformVersionProvider ) - discoveryResolvedTarget.buildTriple = testProduct.buildTriple - let discoveryTargetBuildParameters: BuildParameters - switch discoveryResolvedTarget.buildTriple { - case .tools: - discoveryTargetBuildParameters = toolsBuildParameters - case .destination: - discoveryTargetBuildParameters = destinationBuildParameters - } + let discoveryTargetBuildDescription = try SwiftTargetBuildDescription( package: package, target: discoveryResolvedTarget, toolsVersion: toolsVersion, - destinationBuildParameters: discoveryTargetBuildParameters, - toolsBuildParameters: toolsBuildParameters, + buildParameters: testBuildDescription.buildParameters, testTargetRole: .discovery, shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, @@ -144,20 +136,12 @@ extension BuildPlan { platformVersionProvider: testProduct.platformVersionProvider ) entryPointResolvedTarget.buildTriple = testProduct.buildTriple - let entryPointBuildParameters: BuildParameters - switch entryPointResolvedTarget.buildTriple { - case .tools: - entryPointBuildParameters = toolsBuildParameters - case .destination: - entryPointBuildParameters = destinationBuildParameters - } return try SwiftTargetBuildDescription( package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - destinationBuildParameters: entryPointBuildParameters, - toolsBuildParameters: toolsBuildParameters, + buildParameters: testBuildDescription.buildParameters, testTargetRole: .entryPoint(isSynthesized: true), shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, @@ -202,8 +186,7 @@ extension BuildPlan { package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - destinationBuildParameters: destinationBuildParameters, - toolsBuildParameters: toolsBuildParameters, + buildParameters: destinationBuildParameters, testTargetRole: .entryPoint(isSynthesized: false), shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, @@ -225,8 +208,7 @@ extension BuildPlan { package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - destinationBuildParameters: destinationBuildParameters, - toolsBuildParameters: toolsBuildParameters, + buildParameters: destinationBuildParameters, testTargetRole: .entryPoint(isSynthesized: false), shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index 4da76802288..120a12c29db 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -237,28 +237,6 @@ public class BuildPlan: SPMBuildCore.BuildPlan { /// ObservabilityScope with which to emit diagnostics let observabilityScope: ObservabilityScope - @available(*, deprecated, renamed: "init(destinationBuildParameters:toolsBuildParameters:graph:)") - public convenience init( - buildParameters: BuildParameters, - graph: ModulesGraph, - additionalFileRules: [FileRuleDescription] = [], - buildToolPluginInvocationResults: [ResolvedModule.ID: [BuildToolPluginInvocationResult]] = [:], - prebuildCommandResults: [ResolvedModule.ID: [PrebuildCommandResult]] = [:], - fileSystem: any FileSystem, - observabilityScope: ObservabilityScope - ) throws { - try self.init( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, - graph: graph, - additionalFileRules: additionalFileRules, - buildToolPluginInvocationResults: buildToolPluginInvocationResults, - prebuildCommandResults: prebuildCommandResults, - fileSystem: fileSystem, - observabilityScope: observabilityScope - ) - } - @available(*, deprecated, renamed: "init(destinationBuildParameters:toolsBuildParameters:graph:fileSystem:observabilityScope:)") public convenience init( productsBuildParameters: BuildParameters, @@ -380,7 +358,15 @@ public class BuildPlan: SPMBuildCore.BuildPlan { let requiredMacroProducts = try target.recursiveTargetDependencies() .filter { $0.underlying.type == .macro } - .compactMap { macroProductsByTarget[$0.id] } + .compactMap { + guard let product = macroProductsByTarget[$0.id], + let description = productMap[product.id] else + { + throw InternalError("macro product not found for \($0)") + } + + return description.buildDescription + } var generateTestObservation = false if target.type == .test && shouldGenerateTestObservation { @@ -394,8 +380,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { target: target, toolsVersion: toolsVersion, additionalFileRules: additionalFileRules, - destinationBuildParameters: buildParameters, - toolsBuildParameters: toolsBuildParameters, + buildParameters: buildParameters, buildToolPluginInvocationResults: buildToolPluginInvocationResults[target.id] ?? [], prebuildCommandResults: prebuildCommandResults[target.id] ?? [], requiredMacroProducts: requiredMacroProducts, @@ -454,9 +439,11 @@ public class BuildPlan: SPMBuildCore.BuildPlan { // Plan the derived test targets, if necessary. if destinationBuildParameters.testingParameters.testProductStyle.requiresAdditionalDerivedTestTargets { let derivedTestTargets = try Self.makeDerivedTestTargets( + testProducts: productMap.values.filter { + $0.product.type == .test + }, destinationBuildParameters: destinationBuildParameters, toolsBuildParameters: toolsBuildParameters, - graph, shouldDisableSandbox: self.shouldDisableSandbox, self.fileSystem, self.observabilityScope @@ -595,7 +582,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { arguments.append("-l" + replProductName) // The graph should have the REPL product. - assert(self.graph.allProducts.first(where: { $0.name == replProductName }) != nil) + assert(self.graph.product(for: replProductName, destination: .destination) != nil) // Add the search path to the directory containing the modulemap file. for target in self.targets { diff --git a/Sources/Commands/PackageCommands/DumpCommands.swift b/Sources/Commands/PackageCommands/DumpCommands.swift index 0d080d7d3c3..81b5e5ac3ba 100644 --- a/Sources/Commands/PackageCommands/DumpCommands.swift +++ b/Sources/Commands/PackageCommands/DumpCommands.swift @@ -72,6 +72,7 @@ struct DumpSymbolGraph: SwiftCommand { let result = try symbolGraphExtractor.extractSymbolGraph( module: target, buildPlan: buildPlan, + buildParameters: buildPlan.destinationBuildParameters, outputRedirection: .collect(redirectStderr: true), outputDirectory: symbolGraphDirectory, verboseOutput: swiftCommandState.logLevel <= .info diff --git a/Sources/Commands/PackageCommands/PluginCommand.swift b/Sources/Commands/PackageCommands/PluginCommand.swift index 02d935e0ee1..fedf4df39d6 100644 --- a/Sources/Commands/PackageCommands/PluginCommand.swift +++ b/Sources/Commands/PackageCommands/PluginCommand.swift @@ -317,30 +317,27 @@ struct PluginCommand: SwiftCommand { let toolSearchDirs = [try swiftCommandState.getTargetToolchain().swiftCompilerPath.parentDirectory] + getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: .none) - var buildToolsGraph = packageGraph - try buildToolsGraph.updateBuildTripleRecursively(.tools) - let buildParameters = try swiftCommandState.toolsBuildParameters // Build or bring up-to-date any executable host-side tools on which this plugin depends. Add them and any binary dependencies to the tool-names-to-path map. let buildSystem = try swiftCommandState.createBuildSystem( explicitBuildSystem: .native, cacheBuildManifest: false, - // Force all dependencies to be built for the host, to work around the fact that BuildOperation.plan - // knows to compile build tool plugin dependencies for the host but does not do the same for command - // plugins. - productsBuildParameters: buildParameters, - packageGraphLoader: { buildToolsGraph } + productsBuildParameters: swiftCommandState.productsBuildParameters, + toolsBuildParameters: buildParameters, + packageGraphLoader: { packageGraph } ) let accessibleTools = try plugin.processAccessibleTools( - packageGraph: buildToolsGraph, + packageGraph: packageGraph, fileSystem: swiftCommandState.fileSystem, environment: buildParameters.buildEnvironment, for: try pluginScriptRunner.hostTriple ) { name, _ in // Build the product referenced by the tool, and add the executable to the tool map. Product dependencies are not supported within a package, so if the tool happens to be from the same package, we instead find the executable that corresponds to the product. There is always one, because of autogeneration of implicit executables with the same name as the target if there isn't an explicit one. - try buildSystem.build(subset: .product(name)) - if let builtTool = try buildSystem.buildPlan.buildProducts.first(where: { $0.product.name == name }) { + try buildSystem.build(subset: .product(name, for: .host)) + if let builtTool = try buildSystem.buildPlan.buildProducts.first(where: { + $0.product.name == name && $0.buildParameters.destination == .host + }) { return try builtTool.binaryPath } else { return nil diff --git a/Sources/Commands/Snippets/Cards/SnippetCard.swift b/Sources/Commands/Snippets/Cards/SnippetCard.swift index 72f1afa1017..05e8f7dac06 100644 --- a/Sources/Commands/Snippets/Cards/SnippetCard.swift +++ b/Sources/Commands/Snippets/Cards/SnippetCard.swift @@ -96,7 +96,7 @@ struct SnippetCard: Card { let buildSystem = try swiftCommandState.createBuildSystem(explicitProduct: snippet.name) try buildSystem.build(subset: .product(snippet.name)) let executablePath = try swiftCommandState.productsBuildParameters.buildPath.appending(component: snippet.name) - if let exampleTarget = try buildSystem.getPackageGraph().allTargets.first(where: { $0.name == snippet.name }) { + if let exampleTarget = try buildSystem.getPackageGraph().target(for: snippet.name, destination: .destination) { try ProcessEnv.chdir(exampleTarget.sources.paths[0].parentDirectory) } try exec(path: executablePath.pathString, args: []) diff --git a/Sources/Commands/SwiftRunCommand.swift b/Sources/Commands/SwiftRunCommand.swift index 145bfd93af4..eeec6f315c1 100644 --- a/Sources/Commands/SwiftRunCommand.swift +++ b/Sources/Commands/SwiftRunCommand.swift @@ -218,8 +218,11 @@ public struct SwiftRunCommand: AsyncSwiftCommand { /// Returns the path to the correct executable based on options. private func findProductName(in graph: ModulesGraph) throws -> String { if let executable = options.executable { - let executableExists = graph.allProducts.contains { ($0.type == .executable || $0.type == .snippet) && $0.name == executable } - guard executableExists else { + // There should be only one product with the given name in the graph + // and it should be executable or snippet. + guard let product = graph.product(for: executable, destination: .destination), + product.type == .executable || product.type == .snippet + else { throw RunError.executableNotFound(executable) } return executable diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index d53f1354143..7c946d00ae9 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -1382,7 +1382,12 @@ private func buildTestsIfNeeded( toolsBuildParameters: toolsBuildParameters ) - let subset = testProduct.map(BuildSubset.product) ?? .allIncludingTests + let subset: BuildSubset = if let testProduct { + .product(testProduct) + } else { + .allIncludingTests + } + try buildSystem.build(subset: subset) // Find the test product. diff --git a/Sources/Commands/Utilities/PluginDelegate.swift b/Sources/Commands/Utilities/PluginDelegate.swift index 2d88fbc471e..574d1e8c265 100644 --- a/Sources/Commands/Utilities/PluginDelegate.swift +++ b/Sources/Commands/Utilities/PluginDelegate.swift @@ -385,7 +385,7 @@ final class PluginDelegate: PluginInvocationDelegate { // Find the target in the build operation's package graph; it's an error if we don't find it. let packageGraph = try buildSystem.getPackageGraph() - guard let target = packageGraph.allTargets.first(where: { $0.name == targetName }) else { + guard let target = packageGraph.target(for: targetName, destination: .destination) else { throw StringError("could not find a target named “\(targetName)”") } @@ -430,6 +430,7 @@ final class PluginDelegate: PluginInvocationDelegate { let result = try symbolGraphExtractor.extractSymbolGraph( module: target, buildPlan: try buildSystem.buildPlan, + buildParameters: buildSystem.buildPlan.destinationBuildParameters, outputRedirection: .collect, outputDirectory: outputDir, verboseOutput: self.swiftCommandState.logLevel <= .info diff --git a/Sources/Commands/Utilities/SymbolGraphExtract.swift b/Sources/Commands/Utilities/SymbolGraphExtract.swift index aa968653269..6b8774078ea 100644 --- a/Sources/Commands/Utilities/SymbolGraphExtract.swift +++ b/Sources/Commands/Utilities/SymbolGraphExtract.swift @@ -56,11 +56,11 @@ public struct SymbolGraphExtract { public func extractSymbolGraph( module: ResolvedModule, buildPlan: BuildPlan, + buildParameters: BuildParameters, outputRedirection: TSCBasic.Process.OutputRedirection = .none, outputDirectory: AbsolutePath, verboseOutput: Bool ) throws -> ProcessResult { - let buildParameters = buildPlan.buildParameters(for: module) try self.fileSystem.createDirectory(outputDirectory, recursive: true) // Construct arguments for extracting symbols for a single target. diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index 52b9d8575e1..0130a7bdcd6 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -726,7 +726,10 @@ public final class SwiftCommandState { when building on macOS. """ - private func _buildParams(toolchain: UserToolchain) throws -> BuildParameters { + private func _buildParams( + toolchain: UserToolchain, + destination: BuildParameters.Destination + ) throws -> BuildParameters { let triple = toolchain.targetTriple let dataPath = self.scratchDirectory.appending( @@ -738,6 +741,7 @@ public final class SwiftCommandState { } return try BuildParameters( + destination: destination, dataPath: dataPath, configuration: options.build.configuration, toolchain: toolchain, @@ -797,7 +801,7 @@ public final class SwiftCommandState { private lazy var _toolsBuildParameters: Result = { Result(catching: { - try _buildParams(toolchain: self.getHostToolchain()) + try _buildParams(toolchain: self.getHostToolchain(), destination: .host) }) }() @@ -809,7 +813,7 @@ public final class SwiftCommandState { private lazy var _productsBuildParameters: Result = { Result(catching: { - try _buildParams(toolchain: self.getTargetToolchain()) + try _buildParams(toolchain: self.getTargetToolchain(), destination: .target) }) }() diff --git a/Sources/PackageGraph/BuildTriple.swift b/Sources/PackageGraph/BuildTriple.swift index 87d2daf21f1..a930d8255c0 100644 --- a/Sources/PackageGraph/BuildTriple.swift +++ b/Sources/PackageGraph/BuildTriple.swift @@ -16,12 +16,12 @@ import class PackageModel.Product /// Triple for which code should be compiled for. /// > Note: We're not using "host" and "target" triple terminology in this enum, as that clashes with build /// > system "targets" and can lead to confusion in this context. -public enum BuildTriple { +public enum BuildTriple: String { /// Triple for which build tools are compiled (the host triple). - case tools + case tools = "tools" /// Triple of the destination platform for which end products are compiled (the target triple). - case destination + case destination = "destination" } extension Target { diff --git a/Sources/PackageGraph/ModulesGraph.swift b/Sources/PackageGraph/ModulesGraph.swift index 1c5b2fa78f0..ddc30c1921f 100644 --- a/Sources/PackageGraph/ModulesGraph.swift +++ b/Sources/PackageGraph/ModulesGraph.swift @@ -138,6 +138,14 @@ public struct ModulesGraph { package.dependencies.compactMap { self.package(for: $0) } } + public func product(for name: String, destination: BuildTriple) -> ResolvedProduct? { + self.allProducts.first { $0.name == name && $0.buildTriple == destination } + } + + public func target(for name: String, destination: BuildTriple) -> ResolvedModule? { + self.allTargets.first { $0.name == name && $0.buildTriple == destination } + } + /// All root and root dependency packages provided as input to the graph. public let inputPackages: [ResolvedPackage] @@ -184,6 +192,38 @@ public struct ModulesGraph { } } } + + // Create a new executable product if plugin depends on an executable target. + // This is necessary, even though PackageBuilder creates one already, because + // that product is going to be built for `destination`, and this one has to + // be built for `tools`. + if target.underlying is PluginTarget { + for dependency in target.dependencies { + switch dependency { + case .product(_, conditions: _): + break + + case .target(let target, conditions: _): + if target.type != .executable { + continue + } + + var product = try ResolvedProduct( + packageIdentity: target.packageIdentity, + product: .init( + package: target.packageIdentity, + name: target.name, + type: .executable, + targets: [target.underlying] + ), + targets: IdentifiableSet([target]) + ) + product.buildTriple = .tools + + allProducts.insert(product) + } + } + } } if rootPackages.contains(id: package.id) { @@ -207,30 +247,6 @@ public struct ModulesGraph { self.allProducts = allProducts } - package mutating func updateBuildTripleRecursively(_ buildTriple: BuildTriple) throws { - self.reachableTargets = IdentifiableSet(self.reachableTargets.map { - var target = $0 - target.buildTriple = buildTriple - return target - }) - self.reachableProducts = IdentifiableSet(self.reachableProducts.map { - var product = $0 - product.buildTriple = buildTriple - return product - }) - - self.allTargets = IdentifiableSet(self.allTargets.map { - var target = $0 - target.buildTriple = buildTriple - return target - }) - self.allProducts = IdentifiableSet(self.allProducts.map { - var product = $0 - product.buildTriple = buildTriple - return product - }) - } - /// Computes a map from each executable target in any of the root packages to the corresponding test targets. func computeTestTargetsForExecutableTargets() throws -> [ResolvedModule.ID: [ResolvedModule]] { var result = [ResolvedModule.ID: [ResolvedModule]]() diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index baf1e966d1a..4d51ec354c5 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -26,6 +26,18 @@ public struct BuildParameters: Encodable { case auto } + /// The destination for which code should be compiled for. + public enum Destination: Encodable { + /// The destination for which build tools are compiled. + case host + + /// The destination for which end products are compiled. + case target + } + + /// The destination these parameters are going to be used for. + public var destination: Destination + /// The path to the data directory. public var dataPath: AbsolutePath @@ -118,6 +130,7 @@ public struct BuildParameters: Encodable { public var testingParameters: Testing public init( + destination: Destination, dataPath: AbsolutePath, configuration: BuildConfiguration, toolchain: Toolchain, @@ -144,6 +157,7 @@ public struct BuildParameters: Encodable { omitFramePointers: nil ) + self.destination = destination self.dataPath = dataPath self.configuration = configuration self._toolchain = _Toolchain(toolchain: toolchain) @@ -243,18 +257,18 @@ public struct BuildParameters: Encodable { /// Returns the path to the dynamic library of a product for the current build parameters. func potentialDynamicLibraryPath(for product: ResolvedProduct) throws -> RelativePath { - try RelativePath(validating: "\(self.triple.dynamicLibraryPrefix)\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.dynamicLibraryExtension)") + try RelativePath(validating: "\(self.triple.dynamicLibraryPrefix)\(product.name)\(self.suffix)\(self.triple.dynamicLibraryExtension)") } /// Returns the path to the binary of a product for the current build parameters, relative to the build directory. public func binaryRelativePath(for product: ResolvedProduct) throws -> RelativePath { - let potentialExecutablePath = try RelativePath(validating: "\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.executableExtension)") + let potentialExecutablePath = try RelativePath(validating: "\(product.name)\(self.suffix)\(self.triple.executableExtension)") switch product.type { case .executable, .snippet: return potentialExecutablePath case .library(.static): - return try RelativePath(validating: "lib\(product.name)\(self.suffix(triple: product.buildTriple))\(self.triple.staticLibraryExtension)") + return try RelativePath(validating: "lib\(product.name)\(self.suffix)\(self.triple.staticLibraryExtension)") case .library(.dynamic): return try potentialDynamicLibraryPath(for: product) case .library(.automatic), .plugin: @@ -333,7 +347,7 @@ extension Triple { extension BuildParameters { /// Suffix appended to build manifest nodes to distinguish nodes created for tools from nodes created for /// end products, i.e. nodes for host vs target triples. - package func suffix(triple: BuildTriple) -> String { - if triple == .tools { "-tool" } else { "" } + package var suffix: String { + if destination == .host { "-tool" } else { "" } } } diff --git a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift index 5bdd8a35470..280d7f1954a 100644 --- a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift +++ b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift @@ -25,10 +25,10 @@ public enum BuildSubset { case allIncludingTests /// Represents a specific product. - case product(String) + case product(String, for: BuildParameters.Destination = .target) /// Represents a specific target. - case target(String) + case target(String, for: BuildParameters.Destination = .target) } /// A protocol that represents a build system used by SwiftPM for all build operations. This allows factoring out the @@ -92,28 +92,6 @@ public protocol BuildPlan { func createREPLArguments() throws -> [String] } -extension BuildPlan { - /// Parameters used for building a given target. - public func buildParameters(for target: ResolvedModule) -> BuildParameters { - switch target.buildTriple { - case .tools: - return self.toolsBuildParameters - case .destination: - return self.destinationBuildParameters - } - } - - /// Parameters used for building a given product. - public func buildParameters(for product: ResolvedProduct) -> BuildParameters { - switch product.buildTriple { - case .tools: - return self.toolsBuildParameters - case .destination: - return self.destinationBuildParameters - } - } -} - public protocol BuildSystemFactory { func makeBuildSystem( explicitProduct: String?, diff --git a/Sources/SPMBuildCore/Plugins/PluginInvocation.swift b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift index 3ab08cd47d5..4c194395370 100644 --- a/Sources/SPMBuildCore/Plugins/PluginInvocation.swift +++ b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift @@ -452,7 +452,7 @@ extension ModulesGraph { let toolPaths = accessibleTools.values.map { $0.path }.sorted() // Assign a plugin working directory based on the package, target, and plugin. - let pluginOutputDir = outputDir.appending(components: package.identity.description, target.name, pluginTarget.name) + let pluginOutputDir = outputDir.appending(components: package.identity.description, target.name, target.buildTriple.rawValue, pluginTarget.name) // Determine the set of directories under which plugins are allowed to write. We always include just the output directory, and for now there is no possibility of opting into others. let writableDirectories = [outputDir] @@ -597,9 +597,7 @@ extension ModulesGraph { } // Associate the list of results with the target. The list will have one entry for each plugin used by the target. - var targetID = target.id - targetID.buildTriple = .destination - pluginResultsByTarget[targetID] = (target, buildToolPluginResults) + pluginResultsByTarget[target.id] = (target, buildToolPluginResults) } return pluginResultsByTarget } @@ -677,7 +675,7 @@ public extension PluginTarget { executableOrBinaryTarget = target case .product(let productRef, _): guard - let product = packageGraph.allProducts.first(where: { $0.name == productRef.name }), + let product = packageGraph.product(for: productRef.name, destination: .tools), let executableTarget = product.targets.map({ $0.underlying }).executables.spm_only else { throw StringError("no product named \(productRef.name)") diff --git a/Sources/SPMTestSupport/MockBuildTestHelper.swift b/Sources/SPMTestSupport/MockBuildTestHelper.swift index 92a4dcb0328..64b3b232592 100644 --- a/Sources/SPMTestSupport/MockBuildTestHelper.swift +++ b/Sources/SPMTestSupport/MockBuildTestHelper.swift @@ -15,6 +15,7 @@ import Basics @_spi(SwiftPMInternal) import Build +import struct PackageGraph.ModulesGraph import struct PackageGraph.ResolvedModule import struct PackageGraph.ResolvedProduct import PackageModel @@ -75,6 +76,7 @@ public let defaultTargetTriple: String = hostTriple.tripleString #endif package func mockBuildParameters( + destination: BuildParameters.Destination, buildPath: AbsolutePath? = nil, config: BuildConfiguration = .debug, toolchain: PackageModel.Toolchain = MockToolchain(), @@ -90,6 +92,7 @@ package func mockBuildParameters( omitFramePointers: Bool? = nil ) -> BuildParameters { try! BuildParameters( + destination: destination, dataPath: buildPath ?? AbsolutePath("/path/to/build").appending(triple.tripleString), configuration: config, toolchain: toolchain, @@ -116,7 +119,10 @@ package func mockBuildParameters( ) } -public func mockBuildParameters(environment: BuildEnvironment) -> BuildParameters { +public func mockBuildParameters( + destination: BuildParameters.Destination, + environment: BuildEnvironment +) -> BuildParameters { let triple: Basics.Triple switch environment.platform { case .macOS: @@ -131,9 +137,121 @@ public func mockBuildParameters(environment: BuildEnvironment) -> BuildParameter fatalError("unsupported platform in tests") } - return mockBuildParameters(config: environment.configuration ?? .debug, triple: triple) + return mockBuildParameters( + destination: destination, + config: environment.configuration ?? .debug, + triple: triple + ) } +public func mockBuildPlan( + buildPath: AbsolutePath? = nil, + environment: BuildEnvironment, + toolchain: PackageModel.Toolchain = MockToolchain(), + graph: ModulesGraph, + commonFlags: PackageModel.BuildFlags = .init(), + indexStoreMode: BuildParameters.IndexStoreMode = .off, + omitFramePointers: Bool? = nil, + driverParameters: BuildParameters.Driver = .init(), + linkingParameters: BuildParameters.Linking = .init(), + targetSanitizers: EnabledSanitizers = .init(), + fileSystem fs: any FileSystem, + observabilityScope: ObservabilityScope +) throws -> Build.BuildPlan { + try mockBuildPlan( + buildPath: buildPath, + config: environment.configuration ?? .debug, + platform: environment.platform, + toolchain: toolchain, + graph: graph, + commonFlags: commonFlags, + indexStoreMode: indexStoreMode, + omitFramePointers: omitFramePointers, + driverParameters: driverParameters, + linkingParameters: linkingParameters, + targetSanitizers: targetSanitizers, + fileSystem: fs, + observabilityScope: observabilityScope + ) +} + +public func mockBuildPlan( + buildPath: AbsolutePath? = nil, + config: BuildConfiguration = .debug, + triple: Basics.Triple? = nil, + platform: PackageModel.Platform? = nil, + toolchain: PackageModel.Toolchain = MockToolchain(), + graph: ModulesGraph, + commonFlags: PackageModel.BuildFlags = .init(), + indexStoreMode: BuildParameters.IndexStoreMode = .off, + omitFramePointers: Bool? = nil, + driverParameters: BuildParameters.Driver = .init(), + linkingParameters: BuildParameters.Linking = .init(), + targetSanitizers: EnabledSanitizers = .init(), + fileSystem fs: any FileSystem, + observabilityScope: ObservabilityScope +) throws -> Build.BuildPlan { + let inferredTriple: Basics.Triple + if let platform { + precondition(triple == nil) + + inferredTriple = switch platform { + case .macOS: + Triple.x86_64MacOS + case .linux: + Triple.arm64Linux + case .android: + Triple.arm64Android + case .windows: + Triple.windows + default: + fatalError("unsupported platform in tests") + } + } else { + inferredTriple = triple ?? hostTriple + } + + let commonDebuggingParameters = BuildParameters.Debugging( + triple: inferredTriple, + shouldEnableDebuggingEntitlement: config == .debug, + omitFramePointers: omitFramePointers + ) + + var destinationParameters = mockBuildParameters( + destination: .target, + buildPath: buildPath, + config: config, + toolchain: toolchain, + flags: commonFlags, + triple: inferredTriple, + indexStoreMode: indexStoreMode + ) + destinationParameters.debuggingParameters = commonDebuggingParameters + destinationParameters.driverParameters = driverParameters + destinationParameters.linkingParameters = linkingParameters + destinationParameters.sanitizers = targetSanitizers + + var hostParameters = mockBuildParameters( + destination: .host, + buildPath: buildPath, + config: config, + toolchain: toolchain, + flags: commonFlags, + triple: inferredTriple, + indexStoreMode: indexStoreMode + ) + hostParameters.debuggingParameters = commonDebuggingParameters + hostParameters.driverParameters = driverParameters + hostParameters.linkingParameters = linkingParameters + + return try BuildPlan( + destinationBuildParameters: destinationParameters, + toolsBuildParameters: hostParameters, + graph: graph, + fileSystem: fs, + observabilityScope: observabilityScope + ) +} enum BuildError: Swift.Error { case error(String) } diff --git a/Sources/SPMTestSupport/PackageGraphTester.swift b/Sources/SPMTestSupport/PackageGraphTester.swift index d6db67d74a5..b5442d300b4 100644 --- a/Sources/SPMTestSupport/PackageGraphTester.swift +++ b/Sources/SPMTestSupport/PackageGraphTester.swift @@ -88,19 +88,18 @@ public final class PackageGraphResult { package func checkTarget( _ name: String, + destination: BuildTriple = .destination, file: StaticString = #file, line: UInt = #line, body: (ResolvedTargetResult) -> Void ) { - let targets = find(target: name) + let target = graph.target(for: name, destination: destination) - guard targets.count > 0 else { + guard let target else { return XCTFail("Target \(name) not found", file: file, line: line) } - guard targets.count == 1 else { - return XCTFail("More than a single target with name \(name) found", file: file, line: line) - } - body(ResolvedTargetResult(targets[0])) + + body(ResolvedTargetResult(target)) } package func checkTargets( @@ -114,20 +113,18 @@ public final class PackageGraphResult { public func checkProduct( _ name: String, + destination: BuildTriple = .destination, file: StaticString = #file, line: UInt = #line, body: (ResolvedProductResult) -> Void ) { - let products = find(product: name) + let product = graph.product(for: name, destination: destination) - guard products.count > 0 else { + guard let product else { return XCTFail("Product \(name) not found", file: file, line: line) } - guard products.count == 1 else { - return XCTFail("More than a single product with name \(name) found", file: file, line: line) - } - body(ResolvedProductResult(products[0])) + body(ResolvedProductResult(product)) } public func check(testModules: String..., file: StaticString = #file, line: UInt = #line) { @@ -138,14 +135,6 @@ public final class PackageGraphResult { .sorted(), testModules.sorted(), file: file, line: line) } - package func find(target: String) -> [ResolvedModule] { - return graph.allTargets.filter { $0.name == target } - } - - package func find(product: String) -> [ResolvedProduct] { - return graph.allProducts.filter { $0.name == product } - } - public func find(package: PackageIdentity) -> ResolvedPackage? { return graph.packages.first(where: { $0.identity == package }) } diff --git a/Sources/XCBuildSupport/XcodeBuildSystem.swift b/Sources/XCBuildSupport/XcodeBuildSystem.swift index c47613725f6..c86f3f75b44 100644 --- a/Sources/XCBuildSupport/XcodeBuildSystem.swift +++ b/Sources/XCBuildSupport/XcodeBuildSystem.swift @@ -382,9 +382,9 @@ extension PIFBuilderParameters { extension BuildSubset { var pifTargetName: String { switch self { - case .product(let name): + case .product(let name, _): PackagePIFProjectBuilder.targetName(for: name) - case .target(let name): + case .target(let name, _): name case .allExcludingTests: PIFBuilder.allExcludingTestsTargetName diff --git a/Sources/swift-bootstrap/main.swift b/Sources/swift-bootstrap/main.swift index e6f91509dfd..1f0da76b9ae 100644 --- a/Sources/swift-bootstrap/main.swift +++ b/Sources/swift-bootstrap/main.swift @@ -282,6 +282,7 @@ struct SwiftBootstrapBuildTool: ParsableCommand { ) let buildParameters = try BuildParameters( + destination: .target, dataPath: dataPath, configuration: configuration, toolchain: self.targetToolchain, diff --git a/Tests/BuildTests/BuildOperationTests.swift b/Tests/BuildTests/BuildOperationTests.swift index d04cb83fea9..b454d8fb0d0 100644 --- a/Tests/BuildTests/BuildOperationTests.swift +++ b/Tests/BuildTests/BuildOperationTests.swift @@ -54,20 +54,21 @@ final class BuildOperationTests: XCTestCase { func testDetectUnexpressedDependencies() throws { let scratchDirectory = AbsolutePath("/path/to/build") let triple = hostTriple - let buildParameters = mockBuildParameters( + let targetBuildParameters = mockBuildParameters( + destination: .target, buildPath: scratchDirectory.appending(triple.tripleString), shouldDisableLocalRpath: false, triple: triple ) let fs = InMemoryFileSystem(files: [ - "\(buildParameters.dataPath)/debug/Lunch.build/Lunch.d" : "/Best.framework" + "\(targetBuildParameters.dataPath)/debug/Lunch.build/Lunch.d" : "/Best.framework" ]) let observability = ObservabilitySystem.makeForTesting() let buildOp = mockBuildOperation( - productsBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + productsBuildParameters: targetBuildParameters, + toolsBuildParameters: mockBuildParameters(destination: .host, shouldDisableLocalRpath: false), scratchDirectory: scratchDirectory, fs: fs, observabilityScope: observability.topScope ) @@ -117,14 +118,15 @@ final class BuildOperationTests: XCTestCase { // Perform initial builds for each triple for triple in triples { - let buildParameters = mockBuildParameters( + let targetBuildParameters = mockBuildParameters( + destination: .target, buildPath: scratchDirectory.appending(triple.tripleString), config: .debug, triple: triple ) let buildOp = mockBuildOperation( - productsBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + productsBuildParameters: targetBuildParameters, + toolsBuildParameters: mockBuildParameters(destination: .host), cacheBuildManifest: false, packageGraphLoader: { packageGraph }, scratchDirectory: scratchDirectory, @@ -133,7 +135,7 @@ final class BuildOperationTests: XCTestCase { // Generate initial llbuild manifest let _ = try buildOp.getBuildDescription() // Record the initial llbuild manifest as expected one - llbuildManifestByTriple[triple.tripleString] = try fs.readFileContents(buildParameters.llbuildManifest) + llbuildManifestByTriple[triple.tripleString] = try fs.readFileContents(targetBuildParameters.llbuildManifest) } XCTAssertTrue(fs.exists(scratchDirectory.appending("debug.yaml"))) @@ -149,14 +151,15 @@ final class BuildOperationTests: XCTestCase { // Perform incremental build several times and switch triple for each time for _ in 0..<4 { for triple in triples { - let buildParameters = mockBuildParameters( + let targetBuildParameters = mockBuildParameters( + destination: .target, buildPath: scratchDirectory.appending(triple.tripleString), config: .debug, triple: triple ) let buildOp = mockBuildOperation( - productsBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + productsBuildParameters: targetBuildParameters, + toolsBuildParameters: mockBuildParameters(destination: .host), cacheBuildManifest: true, packageGraphLoader: { packageGraph }, scratchDirectory: scratchDirectory, @@ -166,7 +169,7 @@ final class BuildOperationTests: XCTestCase { let _ = try buildOp.getBuildDescription() // Ensure that llbuild manifest is updated to the expected one - let actualManifest: String = try fs.readFileContents(buildParameters.llbuildManifest) + let actualManifest: String = try fs.readFileContents(targetBuildParameters.llbuildManifest) let expectedManifest = try XCTUnwrap(llbuildManifestByTriple[triple.tripleString]) XCTAssertEqual(actualManifest, expectedManifest) } diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 1ce5cb19fc4..50a50c0fca2 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -41,29 +41,6 @@ extension Build.BuildPlan { .configuration == .release ? "release" : "debug" return buildParameters.dataPath.appending(components: buildConfigurationComponent) } - - /// Create a build plan with a package graph and same build parameters for products and tools. Provided for - /// testing purposes only. - convenience init( - buildParameters: BuildParameters, - graph: ModulesGraph, - additionalFileRules: [FileRuleDescription] = [], - buildToolPluginInvocationResults: [ResolvedModule.ID: [BuildToolPluginInvocationResult]] = [:], - prebuildCommandResults: [ResolvedModule.ID: [PrebuildCommandResult]] = [:], - fileSystem: any FileSystem, - observabilityScope: ObservabilityScope - ) throws { - try self.init( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, - graph: graph, - additionalFileRules: additionalFileRules, - buildToolPluginInvocationResults: buildToolPluginInvocationResults, - prebuildCommandResults: prebuildCommandResults, - fileSystem: fileSystem, - observabilityScope: observabilityScope - ) - } } final class BuildPlanTests: XCTestCase { @@ -191,9 +168,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -314,9 +293,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -407,9 +388,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -482,9 +465,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -613,9 +598,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -756,9 +743,11 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let plan = try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope ) @@ -922,15 +911,14 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) do { - let plan = try BuildPlan( - buildParameters: mockBuildParameters( - buildPath: buildDirPath, - config: .release, - toolchain: UserToolchain.default, - triple: UserToolchain.default.targetTriple, + let plan = try mockBuildPlan( + config: .release, + triple: UserToolchain.default.targetTriple, + toolchain: UserToolchain.default, + graph: graph, + driverParameters: .init( useExplicitModuleBuild: true ), - graph: graph, fileSystem: fs, observabilityScope: observability.topScope ) @@ -1033,11 +1021,11 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) do { - let plan = try BuildPlan( - buildParameters: mockBuildParameters(environment: BuildEnvironment( + let plan = try mockBuildPlan( + environment: BuildEnvironment( platform: .linux, configuration: .release - )), + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1075,11 +1063,11 @@ final class BuildPlanTests: XCTestCase { } do { - let plan = try BuildPlan( - buildParameters: mockBuildParameters(environment: BuildEnvironment( + let plan = try mockBuildPlan( + environment: BuildEnvironment( platform: .macOS, configuration: .debug - )), + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1150,8 +1138,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -1193,8 +1180,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(config: .release), + let result = try BuildPlanResult(plan: mockBuildPlan( + config: .release, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1284,9 +1271,12 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(config: .release, linkerDeadStrip: false), + let result = try BuildPlanResult(plan: mockBuildPlan( + config: .release, graph: graph, + linkingParameters: .init( + linkerDeadStrip: false + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -1397,8 +1387,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1578,11 +1567,11 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) do { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: BuildEnvironment( + let result = try BuildPlanResult(plan: mockBuildPlan( + environment: BuildEnvironment( platform: .linux, configuration: .release - )), + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1597,11 +1586,11 @@ final class BuildPlanTests: XCTestCase { } do { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: BuildEnvironment( + let result = try BuildPlanResult(plan: mockBuildPlan( + environment: BuildEnvironment( platform: .macOS, configuration: .debug - )), + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1653,8 +1642,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1761,9 +1749,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters() - let plan = try BuildPlan( - buildParameters: buildParameters, + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1835,7 +1821,7 @@ final class BuildPlanTests: XCTestCase { "@\(buildPath.appending(components: "exe.product", "Objects.LinkFileList"))", "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift-5.5/macosx", "-target", defaultTargetTriple, - "-Xlinker", "-add_ast_path", "-Xlinker", "/path/to/build/\(buildParameters.triple)/debug/exe.build/exe.swiftmodule", + "-Xlinker", "-add_ast_path", "-Xlinker", "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/exe.build/exe.swiftmodule", "-g", ]) #elseif os(Windows) @@ -1891,9 +1877,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters() - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: buildParameters, + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -1903,8 +1887,8 @@ final class BuildPlanTests: XCTestCase { let lib = try result.target(for: "lib").clangTarget() XCTAssertEqual(try lib.objects, [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/lib.build/lib.S.o"), - AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/lib.build/lib.c.o"), + AbsolutePath("/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/lib.build/lib.S.o"), + AbsolutePath("/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/lib.build/lib.c.o"), ]) } @@ -1955,8 +1939,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2007,8 +1990,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2143,8 +2125,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(config: .release), + let result = try BuildPlanResult(plan: mockBuildPlan( + config: .release, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2400,9 +2382,11 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2508,8 +2492,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2604,8 +2587,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - var result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + var result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2621,8 +2603,8 @@ final class BuildPlanTests: XCTestCase { #endif // Verify that `-lstdc++` is passed instead of `-lc++` when cross-compiling to Linux. - result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: .arm64Linux), + result = try BuildPlanResult(plan: mockBuildPlan( + triple: .arm64Linux, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2670,8 +2652,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: g, fileSystem: fs, observabilityScope: observability.topScope @@ -2806,8 +2787,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -2930,8 +2910,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -3150,8 +3129,7 @@ final class BuildPlanTests: XCTestCase { graphResult.check(targets: "ATarget", "BTarget1", "BTarget2", "CTarget") #endif - let planResult = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let planResult = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3247,8 +3225,8 @@ final class BuildPlanTests: XCTestCase { try graphResult.check(reachableBuildProducts: "aexec", "BLibrary1", "BLibrary2", in: linuxDebug) try graphResult.check(reachableBuildTargets: "ATarget", "BTarget1", "BTarget2", in: linuxDebug) - let planResult = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: linuxDebug), + let planResult = try BuildPlanResult(plan: mockBuildPlan( + environment: linuxDebug, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3262,8 +3240,8 @@ final class BuildPlanTests: XCTestCase { try graphResult.check(reachableBuildProducts: "aexec", "BLibrary2", in: macosDebug) try graphResult.check(reachableBuildTargets: "ATarget", "BTarget2", "BTarget3", in: macosDebug) - let planResult = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: macosDebug), + let planResult = try BuildPlanResult(plan: mockBuildPlan( + environment: macosDebug, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3277,8 +3255,8 @@ final class BuildPlanTests: XCTestCase { try graphResult.check(reachableBuildProducts: "aexec", "CLibrary", in: androidRelease) try graphResult.check(reachableBuildTargets: "ATarget", "CTarget", in: androidRelease) - let planResult = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: androidRelease), + let planResult = try BuildPlanResult(plan: mockBuildPlan( + environment: androidRelease, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3308,8 +3286,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) XCTAssertThrows(BuildPlan.Error.noBuildableTarget) { - _ = try BuildPlan( - buildParameters: mockBuildParameters(), + _ = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -3349,8 +3326,7 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) - _ = try BuildPlan( - buildParameters: mockBuildParameters(), + _ = try mockBuildPlan( graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3391,8 +3367,7 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) - _ = try BuildPlan( - buildParameters: mockBuildParameters(), + _ = try mockBuildPlan( graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3432,8 +3407,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: .windows), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .windows, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -3514,12 +3489,12 @@ final class BuildPlanTests: XCTestCase { ) func createResult(for triple: Basics.Triple) throws -> BuildPlanResult { - try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters( - canRenameEntrypointFunctionName: true, - triple: triple - ), + try BuildPlanResult(plan: mockBuildPlan( + triple: triple, graph: graph, + driverParameters: .init( + canRenameEntrypointFunctionName: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3567,13 +3542,11 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) func check(for mode: BuildParameters.IndexStoreMode, config: BuildConfiguration) throws { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters( - config: config, - toolchain: try UserToolchain.default, - indexStoreMode: mode - ), + let result = try BuildPlanResult(plan: mockBuildPlan( + config: config, + toolchain: try UserToolchain.default, graph: graph, + indexStoreMode: mode, fileSystem: fs, observabilityScope: observability.topScope )) @@ -3639,8 +3612,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3713,8 +3685,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: .init("arm64-apple-ios")), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .init("arm64-apple-ios"), graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3790,8 +3762,8 @@ final class BuildPlanTests: XCTestCase { // Therefore, we expect no error, as the iOS version // constraints above are valid. XCTAssertNoThrow( - _ = try BuildPlan( - buildParameters: mockBuildParameters(triple: .arm64iOS), + _ = try mockBuildPlan( + triple: .arm64iOS, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3800,8 +3772,8 @@ final class BuildPlanTests: XCTestCase { // For completeness, the invalid target should still throw an error. XCTAssertThrows(Diagnostics.fatalError) { - _ = try BuildPlan( - buildParameters: mockBuildParameters(triple: .x86_64MacOS), + _ = try mockBuildPlan( + triple: .x86_64MacOS, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -3863,8 +3835,8 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) XCTAssertThrows(Diagnostics.fatalError) { - _ = try BuildPlan( - buildParameters: mockBuildParameters(triple: .x86_64MacOS), + _ = try mockBuildPlan( + triple: .x86_64MacOS, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -4029,8 +4001,8 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) func createResult(for dest: Basics.Triple) throws -> BuildPlanResult { - try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: dest), + try BuildPlanResult(plan: mockBuildPlan( + triple: dest, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4096,12 +4068,10 @@ final class BuildPlanTests: XCTestCase { // omit frame pointers explicitly set to true do { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters( - triple: .x86_64Linux, - omitFramePointers: true - ), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .x86_64Linux, graph: graph, + omitFramePointers: true, fileSystem: fs, observabilityScope: observability.topScope )) @@ -4153,12 +4123,10 @@ final class BuildPlanTests: XCTestCase { // omit frame pointers explicitly set to false do { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters( - triple: .x86_64Linux, - omitFramePointers: false - ), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .x86_64Linux, graph: graph, + omitFramePointers: false, fileSystem: fs, observabilityScope: observability.topScope )) @@ -4305,9 +4273,9 @@ final class BuildPlanTests: XCTestCase { var flags = BuildFlags() flags.linkerFlags = ["-L", "/path/to/foo", "-L/path/to/foo", "-rpath=foo", "-rpath", "foo"] - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(flags: flags), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + commonFlags: flags, fileSystem: fs, observabilityScope: observability.topScope )) @@ -4369,16 +4337,15 @@ final class BuildPlanTests: XCTestCase { ) ) let mockToolchain = try UserToolchain(swiftSDK: userSwiftSDK) - let extraBuildParameters = mockBuildParameters( - toolchain: mockToolchain, - flags: BuildFlags( - cCompilerFlags: ["-clang-command-line-flag"], - swiftCompilerFlags: ["-swift-command-line-flag"] - ) + let commonFlags = BuildFlags( + cCompilerFlags: ["-clang-command-line-flag"], + swiftCompilerFlags: ["-swift-command-line-flag"] ) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: extraBuildParameters, + + let result = try BuildPlanResult(plan: mockBuildPlan( + toolchain: mockToolchain, graph: graph, + commonFlags: commonFlags, fileSystem: fs, observabilityScope: observability.topScope )) @@ -4427,16 +4394,14 @@ final class BuildPlanTests: XCTestCase { .anySequence, ]) - let staticBuildParameters = { - var copy = extraBuildParameters - copy.linkingParameters.shouldLinkStaticSwiftStdlib = true - // pick a triple with support for static linking - copy.triple = .x86_64Linux - return copy - }() - let staticResult = try BuildPlanResult(plan: BuildPlan( - buildParameters: staticBuildParameters, + let staticResult = try BuildPlanResult(plan: mockBuildPlan( + triple: .x86_64Linux, + toolchain: mockToolchain, graph: graph, + commonFlags: commonFlags, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4511,19 +4476,16 @@ final class BuildPlanTests: XCTestCase { toolset: toolset ) let toolchain = try UserToolchain(swiftSDK: swiftSDK) - let buildParameters = mockBuildParameters( + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: targetTriple, toolchain: toolchain, - flags: BuildFlags( + graph: graph, + commonFlags: BuildFlags( cCompilerFlags: [cliFlag(tool: .cCompiler)], cxxCompilerFlags: [cliFlag(tool: .cxxCompiler)], swiftCompilerFlags: [cliFlag(tool: .swiftCompiler)], linkerFlags: [cliFlag(tool: .linker)] ), - triple: targetTriple - ) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: buildParameters, - graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope )) @@ -4667,9 +4629,8 @@ final class BuildPlanTests: XCTestCase { ]) ) let toolchain = try UserToolchain(swiftSDK: swiftSDK) - let buildParameters = mockBuildParameters(toolchain: toolchain) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: buildParameters, + let result = try BuildPlanResult(plan: mockBuildPlan( + toolchain: toolchain, graph: graph, fileSystem: fileSystem, observabilityScope: observability.topScope @@ -4738,8 +4699,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4804,9 +4764,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters() - let plan = try BuildPlan( - buildParameters: buildParameters, + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4822,7 +4780,7 @@ final class BuildPlanTests: XCTestCase { [ .anySequence, "-emit-objc-header", - "-emit-objc-header-path", "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", + "-emit-objc-header-path", "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4832,7 +4790,7 @@ final class BuildPlanTests: XCTestCase { [ .anySequence, "-emit-objc-header", - "-emit-objc-header-path", "/path/to/build/\(buildParameters.triple)/Foo.build/Foo-Swift.h", + "-emit-objc-header-path", "/path/to/build/\(result.plan.destinationBuildParameters.triple)/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4842,12 +4800,12 @@ final class BuildPlanTests: XCTestCase { #if os(macOS) XCTAssertMatch( barTarget, - [.anySequence, "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] + [.anySequence, "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] ) #else XCTAssertNoMatch( barTarget, - [.anySequence, "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] + [.anySequence, "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence] ) #endif @@ -4905,9 +4863,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters() - let plan = try BuildPlan( - buildParameters: buildParameters, + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -4924,7 +4880,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4935,7 +4891,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -4947,7 +4903,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -4956,7 +4912,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5016,9 +4972,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters() - let plan = try BuildPlan( - buildParameters: buildParameters, + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5039,7 +4993,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -5050,7 +5004,7 @@ final class BuildPlanTests: XCTestCase { .anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Foo.build/Foo-Swift.h", + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/Foo-Swift.h", .anySequence, ] ) @@ -5062,7 +5016,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5071,7 +5025,7 @@ final class BuildPlanTests: XCTestCase { barTarget, [ .anySequence, - "-fmodule-map-file=/path/to/build/\(buildParameters.triple)/debug/Foo.build/module.modulemap", + "-fmodule-map-file=/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Foo.build/module.modulemap", .anySequence, ] ) @@ -5120,8 +5074,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: .x86_64Linux), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .x86_64Linux, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5205,8 +5159,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5357,8 +5310,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5425,8 +5377,8 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(triple: .wasi), + let plan = try mockBuildPlan( + triple: .wasi, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5492,8 +5444,7 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(), + let plan = try mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5558,9 +5509,12 @@ final class BuildPlanTests: XCTestCase { let supportingTriples: [Basics.Triple] = [.x86_64Linux, .arm64Linux, .wasi] for triple in supportingTriples { - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: triple), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: triple, graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -5683,8 +5637,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: targetTriple), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: targetTriple, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5812,8 +5766,8 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(triple: targetTriple), + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: targetTriple, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5895,8 +5849,8 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let plan = try BuildPlan( - buildParameters: mockBuildParameters(buildPath: buildPath), + let plan = try mockBuildPlan( + buildPath: buildPath, graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -5949,15 +5903,15 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - // Unrealistic: we can't enable all of these at once on all platforms. - // This test codifies current behavior, not ideal behavior, and - // may need to be amended if we change it. - var parameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) - parameters.sanitizers = EnabledSanitizers([sanitizer]) - - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: parameters, + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), + // Unrealistic: we can't enable all of these at once on all platforms. + // This test codifies current behavior, not ideal behavior, and + // may need to be amended if we change it. + targetSanitizers: EnabledSanitizers([sanitizer]), fileSystem: fs, observabilityScope: observability.topScope )) @@ -6003,13 +5957,12 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) let toolchain = try UserToolchain.default - let buildParameters = mockBuildParameters( + let result = try BuildPlanResult(plan: mockBuildPlan( toolchain: toolchain, - linkTimeOptimizationMode: .full - ) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: buildParameters, graph: graph, + linkingParameters: .init( + linkTimeOptimizationMode: .full + ), fileSystem: fileSystem, observabilityScope: observability.topScope )) @@ -6076,11 +6029,11 @@ final class BuildPlanTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(environment: BuildEnvironment( + let result = try BuildPlanResult(plan: mockBuildPlan( + environment: BuildEnvironment( platform: .linux, configuration: .release - )), + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -6126,9 +6079,11 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldDisableLocalRpath: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldDisableLocalRpath: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -6240,9 +6195,11 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -6292,8 +6249,7 @@ final class BuildPlanTests: XCTestCase { observabilityScope: observability.topScope ) - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: mockBuildParameters(), + let result = try BuildPlanResult(plan: mockBuildPlan( graph: graph, fileSystem: fs, observabilityScope: observability.topScope diff --git a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift index 88f91f2ddde..e50e536b4ee 100644 --- a/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift +++ b/Tests/BuildTests/ClangTargetBuildDescriptionTests.swift @@ -92,6 +92,7 @@ final class ClangTargetBuildDescriptionTests: XCTestCase { target: target, toolsVersion: .current, buildParameters: buildParameters ?? mockBuildParameters( + destination: .target, toolchain: try UserToolchain.default, indexStoreMode: .on ), diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 3075a1f4c77..d322aca607b 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -21,6 +21,7 @@ import enum PackageGraph.BuildTriple import class PackageModel.Manifest import struct PackageModel.TargetDescription import enum PackageModel.ProductType +import struct SPMBuildCore.BuildParameters import func SPMTestSupport.loadPackageGraph @_spi(SwiftPMInternal) @@ -30,6 +31,7 @@ import func SPMTestSupport.embeddedCxxInteropPackageGraph import func SPMTestSupport.macrosPackageGraph import func SPMTestSupport.macrosTestsPackageGraph import func SPMTestSupport.mockBuildParameters +import func SPMTestSupport.mockBuildPlan import func SPMTestSupport.toolsExplicitLibrariesGraph import func SPMTestSupport.trivialPackageGraph @@ -45,11 +47,15 @@ final class CrossCompilationBuildPlanTests: XCTestCase { var (graph, fs, observabilityScope) = try trivialPackageGraph() let triple = try Triple("wasm32-unknown-none-wasm") - var parameters = mockBuildParameters(triple: triple) - parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true - var result = try BuildPlanResult(plan: BuildPlan( - buildParameters: parameters, + + let linkingParameters = BuildParameters.Linking( + shouldLinkStaticSwiftStdlib: true + ) + + var result = try BuildPlanResult(plan: mockBuildPlan( + triple: triple, graph: graph, + linkingParameters: linkingParameters, fileSystem: fs, observabilityScope: observabilityScope )) @@ -75,9 +81,10 @@ final class CrossCompilationBuildPlanTests: XCTestCase { (graph, fs, observabilityScope) = try embeddedCxxInteropPackageGraph() - result = try BuildPlanResult(plan: BuildPlan( - buildParameters: parameters, + result = try BuildPlanResult(plan: mockBuildPlan( + triple: triple, graph: graph, + linkingParameters: linkingParameters, fileSystem: fs, observabilityScope: observabilityScope )) @@ -105,13 +112,14 @@ final class CrossCompilationBuildPlanTests: XCTestCase { func testWasmTargetRelease() throws { let (graph, fs, observabilityScope) = try trivialPackageGraph() - var parameters = mockBuildParameters( - config: .release, triple: .wasi, linkerDeadStrip: true - ) - parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: parameters, + let result = try BuildPlanResult(plan: mockBuildPlan( + config: .release, + triple: .wasi, graph: graph, + linkingParameters: .init( + linkerDeadStrip: true, + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observabilityScope )) @@ -138,11 +146,12 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let (graph, fs, observabilityScope) = try trivialPackageGraph() - var parameters = mockBuildParameters(triple: .wasi) - parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true - let result = try BuildPlanResult(plan: BuildPlan( - buildParameters: parameters, + let result = try BuildPlanResult(plan: mockBuildPlan( + triple: .wasi, graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observabilityScope )) @@ -224,8 +233,15 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let destinationTriple = Triple.arm64Linux let toolsTriple = Triple.x86_64MacOS let plan = try BuildPlan( - destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), - toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + destinationBuildParameters: mockBuildParameters( + destination: .target, + shouldLinkStaticSwiftStdlib: true, + triple: destinationTriple + ), + toolsBuildParameters: mockBuildParameters( + destination: .host, + triple: toolsTriple + ), graph: graph, fileSystem: fs, observabilityScope: scope @@ -269,8 +285,15 @@ final class CrossCompilationBuildPlanTests: XCTestCase { let destinationTriple = Triple.arm64Linux let toolsTriple = Triple.x86_64MacOS let plan = try BuildPlan( - destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), - toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + destinationBuildParameters: mockBuildParameters( + destination: .target, + shouldLinkStaticSwiftStdlib: true, + triple: destinationTriple + ), + toolsBuildParameters: mockBuildParameters( + destination: .host, + triple: toolsTriple + ), graph: graph, fileSystem: fs, observabilityScope: scope @@ -317,8 +340,15 @@ final class CrossCompilationBuildPlanTests: XCTestCase { for (linkage, productFileName) in [(ProductType.LibraryType.static, "libSwiftSyntax-tool.a"), (.dynamic, "libSwiftSyntax-tool.dylib")] { let (graph, fs, scope) = try toolsExplicitLibrariesGraph(linkage: linkage) let plan = try BuildPlan( - destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: destinationTriple), - toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + destinationBuildParameters: mockBuildParameters( + destination: .target, + shouldLinkStaticSwiftStdlib: true, + triple: destinationTriple + ), + toolsBuildParameters: mockBuildParameters( + destination: .host, + triple: toolsTriple + ), graph: graph, fileSystem: fs, observabilityScope: scope diff --git a/Tests/BuildTests/LLBuildManifestBuilderTests.swift b/Tests/BuildTests/LLBuildManifestBuilderTests.swift index 5ef41c5e8a8..ecb3609606e 100644 --- a/Tests/BuildTests/LLBuildManifestBuilderTests.swift +++ b/Tests/BuildTests/LLBuildManifestBuilderTests.swift @@ -48,13 +48,11 @@ final class LLBuildManifestBuilderTests: XCTestCase { // macOS, release build - var buildParameters = mockBuildParameters(environment: BuildEnvironment( - platform: .macOS, - configuration: .release - )) - var plan = try BuildPlan( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + var plan = try mockBuildPlan( + environment: BuildEnvironment( + platform: .macOS, + configuration: .release + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -71,9 +69,9 @@ final class LLBuildManifestBuilderTests: XCTestCase { try llbuild.createProductCommand(buildProduct) var basicReleaseCommandNames = [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-\(buildParameters.triple)-release.exe", + AbsolutePath("/path/to/build/\(plan.destinationBuildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-\(plan.destinationBuildParameters.triple)-release.exe", ] XCTAssertEqual( @@ -83,13 +81,11 @@ final class LLBuildManifestBuilderTests: XCTestCase { // macOS, debug build - buildParameters = mockBuildParameters(environment: BuildEnvironment( - platform: .macOS, - configuration: .debug - )) - plan = try BuildPlan( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + plan = try mockBuildPlan( + environment: BuildEnvironment( + platform: .macOS, + configuration: .debug + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -101,17 +97,17 @@ final class LLBuildManifestBuilderTests: XCTestCase { llbuild = LLBuildManifestBuilder(plan, fileSystem: fs, observabilityScope: observability.topScope) try llbuild.createProductCommand(buildProduct) - let entitlementsCommandName = "C.exe-\(buildParameters.triple)-debug.exe-entitlements" + let entitlementsCommandName = "C.exe-\(plan.destinationBuildParameters.triple)-debug.exe-entitlements" var basicDebugCommandNames = [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-\(buildParameters.triple)-debug.exe", + AbsolutePath("/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-\(plan.destinationBuildParameters.triple)-debug.exe", ] XCTAssertEqual( llbuild.manifest.commands.map(\.key).sorted(), (basicDebugCommandNames + [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe-entitlement.plist").pathString, + AbsolutePath("/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe-entitlement.plist").pathString, entitlementsCommandName, ]).sorted() ) @@ -124,26 +120,24 @@ final class LLBuildManifestBuilderTests: XCTestCase { XCTAssertEqual( entitlementsCommand.inputs, [ - .file("/path/to/build/\(buildParameters.triple)/debug/exe", isMutated: true), - .file("/path/to/build/\(buildParameters.triple)/debug/exe-entitlement.plist"), + .file("/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe", isMutated: true), + .file("/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe-entitlement.plist"), ] ) XCTAssertEqual( entitlementsCommand.outputs, [ - .virtual("exe-\(buildParameters.triple)-debug.exe-CodeSigning"), + .virtual("exe-\(plan.destinationBuildParameters.triple)-debug.exe-CodeSigning"), ] ) // Linux, release build - buildParameters = mockBuildParameters(environment: BuildEnvironment( - platform: .linux, - configuration: .release - )) - plan = try BuildPlan( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + plan = try mockBuildPlan( + environment: BuildEnvironment( + platform: .linux, + configuration: .release + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -156,9 +150,9 @@ final class LLBuildManifestBuilderTests: XCTestCase { try llbuild.createProductCommand(buildProduct) basicReleaseCommandNames = [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-\(buildParameters.triple)-release.exe", + AbsolutePath("/path/to/build/\(plan.destinationBuildParameters.triple)/release/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-\(plan.destinationBuildParameters.triple)-release.exe", ] XCTAssertEqual( @@ -168,13 +162,11 @@ final class LLBuildManifestBuilderTests: XCTestCase { // Linux, debug build - buildParameters = mockBuildParameters(environment: BuildEnvironment( - platform: .linux, - configuration: .debug - )) - plan = try BuildPlan( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + plan = try mockBuildPlan( + environment: BuildEnvironment( + platform: .linux, + configuration: .debug + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -187,9 +179,9 @@ final class LLBuildManifestBuilderTests: XCTestCase { try llbuild.createProductCommand(buildProduct) basicDebugCommandNames = [ - AbsolutePath("/path/to/build/\(buildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, - "", - "C.exe-\(buildParameters.triple)-debug.exe", + AbsolutePath("/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe.product/Objects.LinkFileList").pathString, + "", + "C.exe-\(plan.destinationBuildParameters.triple)-debug.exe", ] XCTAssertEqual( @@ -205,8 +197,15 @@ final class LLBuildManifestBuilderTests: XCTestCase { let toolsTriple = Triple.arm64Linux let plan = try BuildPlan( - destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: productsTriple), - toolsBuildParameters: mockBuildParameters(triple: toolsTriple), + destinationBuildParameters: mockBuildParameters( + destination: .target, + shouldLinkStaticSwiftStdlib: true, + triple: productsTriple + ), + toolsBuildParameters: mockBuildParameters( + destination: .host, + triple: toolsTriple + ), graph: graph, fileSystem: fs, observabilityScope: scope diff --git a/Tests/BuildTests/ModuleAliasingBuildTests.swift b/Tests/BuildTests/ModuleAliasingBuildTests.swift index 73b5ed2b7fb..8bd0a32f716 100644 --- a/Tests/BuildTests/ModuleAliasingBuildTests.swift +++ b/Tests/BuildTests/ModuleAliasingBuildTests.swift @@ -186,9 +186,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -388,9 +390,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -472,9 +476,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -598,9 +604,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -694,10 +702,11 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: buildParameters, + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -725,33 +734,33 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertMatch( fooLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] ) XCTAssertMatch( barLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] ) XCTAssertMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #else XCTAssertNoMatch( fooLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/FooLogging.build/FooLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( barLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/BarLogging.build/BarLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #endif } @@ -813,10 +822,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: buildParameters, + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -844,23 +854,23 @@ final class ModuleAliasingBuildTests: XCTestCase { XCTAssertMatch( otherLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] ) XCTAssertMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #else XCTAssertNoMatch( otherLoggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/OtherLogging.build/OtherLogging-Swift.h", .anySequence] ) XCTAssertNoMatch( loggingArgs, [.anySequence, "-emit-objc-header", "-emit-objc-header-path", - "/path/to/build/\(buildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] + "/path/to/build/\(result.plan.destinationBuildParameters.triple)/debug/Logging.build/Logging-Swift.h", .anySequence] ) #endif } @@ -988,9 +998,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -1317,9 +1329,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -1422,9 +1436,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -1623,9 +1639,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -1798,9 +1816,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2011,9 +2031,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2228,9 +2250,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2405,9 +2429,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2549,9 +2575,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2692,9 +2720,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2842,9 +2872,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -2994,9 +3026,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3107,9 +3141,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3218,9 +3254,11 @@ final class ModuleAliasingBuildTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3296,9 +3334,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3442,9 +3482,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3616,9 +3658,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3749,9 +3793,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -3877,9 +3923,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4018,9 +4066,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4190,9 +4240,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4360,9 +4412,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4527,9 +4581,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) @@ -4622,9 +4678,11 @@ final class ModuleAliasingBuildTests: XCTestCase { observabilityScope: observability.topScope ) XCTAssertNoDiagnostics(observability.diagnostics) - let result = try BuildPlanResult(plan: try BuildPlan( - buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true), + let result = try BuildPlanResult(plan: try mockBuildPlan( graph: graph, + linkingParameters: .init( + shouldLinkStaticSwiftStdlib: true + ), fileSystem: fs, observabilityScope: observability.topScope )) diff --git a/Tests/BuildTests/ProductBuildDescriptionTests.swift b/Tests/BuildTests/ProductBuildDescriptionTests.swift index 444565cef7b..e416331dc29 100644 --- a/Tests/BuildTests/ProductBuildDescriptionTests.swift +++ b/Tests/BuildTests/ProductBuildDescriptionTests.swift @@ -61,7 +61,7 @@ final class ProductBuildDescriptionTests: XCTestCase { package: package, product: product, toolsVersion: .v5_9, - buildParameters: mockBuildParameters(environment: .init(platform: .macOS)), + buildParameters: mockBuildParameters(destination: .target, environment: .init(platform: .macOS)), fileSystem: fs, observabilityScope: observability.topScope ) diff --git a/Tests/FunctionalTests/PluginTests.swift b/Tests/FunctionalTests/PluginTests.swift index 7abb495a067..0ec57d05101 100644 --- a/Tests/FunctionalTests/PluginTests.swift +++ b/Tests/FunctionalTests/PluginTests.swift @@ -225,7 +225,7 @@ class PluginTests: XCTestCase { try testWithTemporaryDirectory { tmpPath in let packageDir = tmpPath.appending(components: "MyPackage") - let pathOfGeneratedFile = packageDir.appending(components: [".build", "plugins", "outputs", "mypackage", "SomeTarget", "Plugin", "best.txt"]) + let pathOfGeneratedFile = packageDir.appending(components: [".build", "plugins", "outputs", "mypackage", "SomeTarget", "destination", "Plugin", "best.txt"]) try createPackageUnderTest(packageDir: packageDir, toolsVersion: .v5_9) let (_, stderr) = try executeSwiftBuild(packageDir, env: ["SWIFT_DRIVER_SWIFTSCAN_LIB" : "/this/is/a/bad/path"]) diff --git a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift index 69c19852f59..4c9b083aeea 100644 --- a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift +++ b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift @@ -118,7 +118,7 @@ final class CrossCompilationPackageGraphTests: XCTestCase { result.checkTargets("MMIOMacros") { results in XCTAssertEqual(results.count, 1) } - result.checkTarget("MMIOMacrosTests") { result in + result.checkTarget("MMIOMacrosTests", destination: .tools) { result in result.check(buildTriple: .tools) result.checkDependency("MMIOMacros") { result in result.checkTarget { result in diff --git a/Tests/PackageGraphTests/ModulesGraphTests.swift b/Tests/PackageGraphTests/ModulesGraphTests.swift index 98e76341893..e0017803f9b 100644 --- a/Tests/PackageGraphTests/ModulesGraphTests.swift +++ b/Tests/PackageGraphTests/ModulesGraphTests.swift @@ -81,12 +81,12 @@ final class ModulesGraphTests: XCTestCase { } let fooPackage = try XCTUnwrap(g.package(for: .plain("Foo"))) - let fooTarget = try XCTUnwrap(g.allTargets.first{ $0.name == "Foo" }) - let fooDepTarget = try XCTUnwrap(g.allTargets.first{ $0.name == "FooDep" }) + let fooTarget = try XCTUnwrap(g.target(for: "Foo", destination: .destination)) + let fooDepTarget = try XCTUnwrap(g.target(for: "FooDep", destination: .destination)) XCTAssertEqual(g.package(for: fooTarget)?.id, fooPackage.id) XCTAssertEqual(g.package(for: fooDepTarget)?.id, fooPackage.id) let barPackage = try XCTUnwrap(g.package(for: .plain("Bar"))) - let barTarget = try XCTUnwrap(g.allTargets.first{ $0.name == "Bar" }) + let barTarget = try XCTUnwrap(g.target(for: "Bar", destination: .destination)) XCTAssertEqual(g.package(for: barTarget)?.id, barPackage.id) } diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index 0d21bf053c3..9f168c99452 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -33,6 +33,7 @@ final class PluginInvocationTests: XCTestCase { let fileSystem = InMemoryFileSystem(emptyFiles: "/Foo/Plugins/FooPlugin/source.swift", "/Foo/Sources/FooTool/source.swift", + "/Foo/Sources/FooToolLib/source.swift", "/Foo/Sources/Foo/source.swift", "/Foo/Sources/Foo/SomeFile.abc" ) @@ -64,9 +65,14 @@ final class PluginInvocationTests: XCTestCase { ), TargetDescription( name: "FooTool", - dependencies: [], + dependencies: ["FooToolLib"], type: .executable ), + TargetDescription( + name: "FooToolLib", + dependencies: [], + type: .regular + ), ] ) ], @@ -77,18 +83,24 @@ final class PluginInvocationTests: XCTestCase { XCTAssertNoDiagnostics(observability.diagnostics) PackageGraphTester(graph) { graph in graph.check(packages: "Foo") - // "FooTool" duplicated as it's present for both build tools and end products triples. - graph.check(targets: "Foo", "FooPlugin", "FooTool", "FooTool") + // "FooTool{Lib}" duplicated as it's present for both build tools and end products triples. + graph.check(targets: "Foo", "FooPlugin", "FooTool", "FooTool", "FooToolLib", "FooToolLib") graph.checkTarget("Foo") { target in target.check(dependencies: "FooPlugin") } - graph.checkTarget("FooPlugin") { target in + graph.checkTarget("FooPlugin", destination: .tools) { target in target.check(type: .plugin) target.check(dependencies: "FooTool") } - graph.checkTargets("FooTool") { targets in - for target in targets { + for destination: BuildTriple in [.tools, .destination] { + graph.checkTarget("FooTool", destination: destination) { target in target.check(type: .executable) + target.check(buildTriple: destination) + target.checkDependency("FooToolLib") { dependency in + dependency.checkTarget { + $0.check(buildTriple: destination) + } + } } } } @@ -196,6 +208,7 @@ final class PluginInvocationTests: XCTestCase { let outputDir = AbsolutePath("/Foo/.build") let pluginRunner = MockPluginScriptRunner() let buildParameters = mockBuildParameters( + destination: .host, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) let results = try graph.invokeBuildToolPlugins( @@ -899,6 +912,7 @@ final class PluginInvocationTests: XCTestCase { let result = try packageGraph.invokeBuildToolPlugins( outputDir: outputDir, buildParameters: mockBuildParameters( + destination: .host, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ), additionalFileRules: [], @@ -1243,6 +1257,7 @@ final class PluginInvocationTests: XCTestCase { return try packageGraph.invokeBuildToolPlugins( outputDir: outputDir, buildParameters: mockBuildParameters( + destination: .host, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ), additionalFileRules: [], diff --git a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift index 99c43463bf3..8ca021945c8 100644 --- a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift +++ b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift @@ -42,10 +42,15 @@ class SourceKitLSPAPITests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - let buildParameters = mockBuildParameters(shouldLinkStaticSwiftStdlib: true) let plan = try BuildPlan( - destinationBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, + destinationBuildParameters: mockBuildParameters( + destination: .target, + shouldLinkStaticSwiftStdlib: true + ), + toolsBuildParameters: mockBuildParameters( + destination: .host, + shouldLinkStaticSwiftStdlib: true + ), graph: graph, fileSystem: fs, observabilityScope: observability.topScope @@ -59,7 +64,7 @@ class SourceKitLSPAPITests: XCTestCase { "-module-name", "exe", "-emit-dependencies", "-emit-module", - "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/exe.build/exe.swiftmodule" + "-emit-module-path", "/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe.build/exe.swiftmodule" ], isPartOfRootPackage: true ) @@ -70,7 +75,7 @@ class SourceKitLSPAPITests: XCTestCase { "-module-name", "lib", "-emit-dependencies", "-emit-module", - "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/Modules/lib.swiftmodule" + "-emit-module-path", "/path/to/build/\(plan.destinationBuildParameters.triple)/debug/Modules/lib.swiftmodule" ], isPartOfRootPackage: true ) @@ -78,8 +83,13 @@ class SourceKitLSPAPITests: XCTestCase { } extension SourceKitLSPAPI.BuildDescription { - @discardableResult func checkArguments(for targetName: String, graph: ModulesGraph, partialArguments: [String], isPartOfRootPackage: Bool) throws -> Bool { - let target = try XCTUnwrap(graph.allTargets.first(where: { $0.name == targetName })) + @discardableResult func checkArguments( + for targetName: String, + graph: ModulesGraph, + partialArguments: [String], + isPartOfRootPackage: Bool + ) throws -> Bool { + let target = try XCTUnwrap(graph.target(for: targetName, destination: .destination)) let buildTarget = try XCTUnwrap(self.getBuildTarget(for: target, in: graph)) guard let file = buildTarget.sources.first else { From 4e521bb4dca8e34787a95130698ce747e15845c7 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 31 May 2024 14:59:39 -0700 Subject: [PATCH 12/14] =?UTF-8?q?[Build]=20Adjust=20`computeLLBuildTargetN?= =?UTF-8?q?ame`=20to=20attempt=20`host`=20destinati=E2=80=A6=20(#7619)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …on for test products ### Motivation: Just like macros and plugins, tests products can also be built for the host depending on their test target(s) destinations (which are inferred based on dependencies). In order to properly support `--test-product` option we need to fallback to `host` lookup for test products just like we do for macros and plugins. ### Modifications: - Added a fallback lookup to `computeLLBuildTargetName` ### Result: `--test-product` now supports both `host` and `target` destination products. --- Sources/Build/BuildOperation.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index efa084748bd..99c9a4a1c27 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -539,9 +539,12 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // It's possible to request a build of a macro or a plugin via `swift build` // which won't have the right destination set because it's impossible to indicate it. + // + // Same happens with `--test-product` - if one of the test targets directly references + // a macro then all if its targets and the product itself become `host`. if product == nil && destination == .target { if let toolsProduct = graph.product(for: productName, destination: .tools), - toolsProduct.type == .macro || toolsProduct.type == .plugin + toolsProduct.type == .macro || toolsProduct.type == .plugin || toolsProduct.type == .test { product = toolsProduct buildParameters = self.toolsBuildParameters From 1f21a121e4df152ff97c2d992b4ded2a5318aa26 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 7 Jun 2024 11:06:30 -0700 Subject: [PATCH 13/14] [Build/PackageGraph] Sink fallback logic for macro/plugin/test products and packages identification into `ModulesGraph` This is a temporary fix until we can figure out a proper way to handle situations were all we get is a name of a product or a target. Resolves: rdar://129400066 (cherry picked from commit 09b3ed113d3b38d52bd99e6803ef8c521bd22779) --- Sources/Build/BuildOperation.swift | 53 +++++++------------------ Sources/PackageGraph/ModulesGraph.swift | 50 ++++++++++++++++++++++- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 99c9a4a1c27..eb98ec1cad1 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -526,36 +526,22 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // FIXME: This is super unfortunate that we might need to load the package graph. let graph = try getPackageGraph() - var product = graph.product( + let product = graph.product( for: productName, destination: destination == .host ? .tools : .destination ) - var buildParameters = if destination == .host { - self.toolsBuildParameters - } else { - self.productsBuildParameters - } - - // It's possible to request a build of a macro or a plugin via `swift build` - // which won't have the right destination set because it's impossible to indicate it. - // - // Same happens with `--test-product` - if one of the test targets directly references - // a macro then all if its targets and the product itself become `host`. - if product == nil && destination == .target { - if let toolsProduct = graph.product(for: productName, destination: .tools), - toolsProduct.type == .macro || toolsProduct.type == .plugin || toolsProduct.type == .test - { - product = toolsProduct - buildParameters = self.toolsBuildParameters - } - } - guard let product else { observabilityScope.emit(error: "no product named '\(productName)'") throw Diagnostics.fatalError } + let buildParameters = if product.buildTriple == .tools { + self.toolsBuildParameters + } else { + self.productsBuildParameters + } + // If the product is automatic, we build the main target because automatic products // do not produce a binary right now. if product.type == .library(.automatic) { @@ -570,33 +556,22 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // FIXME: This is super unfortunate that we might need to load the package graph. let graph = try getPackageGraph() - var target = graph.target( + let target = graph.target( for: targetName, destination: destination == .host ? .tools : .destination ) - var buildParameters = if destination == .host { - self.toolsBuildParameters - } else { - self.productsBuildParameters - } - - // It's possible to request a build of a macro or a plugin via `swift build` - // which won't have the right destination because it's impossible to indicate it. - if target == nil && destination == .target { - if let toolsTarget = graph.target(for: targetName, destination: .tools), - toolsTarget.type == .macro || toolsTarget.type == .plugin - { - target = toolsTarget - buildParameters = self.toolsBuildParameters - } - } - guard let target else { observabilityScope.emit(error: "no target named '\(targetName)'") throw Diagnostics.fatalError } + let buildParameters = if target.buildTriple == .tools { + self.toolsBuildParameters + } else { + self.productsBuildParameters + } + return target.getLLBuildTargetName(buildParameters: buildParameters) } } diff --git a/Sources/PackageGraph/ModulesGraph.swift b/Sources/PackageGraph/ModulesGraph.swift index ddc30c1921f..8d0804aa79a 100644 --- a/Sources/PackageGraph/ModulesGraph.swift +++ b/Sources/PackageGraph/ModulesGraph.swift @@ -139,11 +139,57 @@ public struct ModulesGraph { } public func product(for name: String, destination: BuildTriple) -> ResolvedProduct? { - self.allProducts.first { $0.name == name && $0.buildTriple == destination } + func findProduct(name: String, destination: BuildTriple) -> ResolvedProduct? { + self.allProducts.first { $0.name == name && $0.buildTriple == destination } + } + + if let product = findProduct(name: name, destination: destination) { + return product + } + + // FIXME: This is a temporary workaround and needs to be handled by the callers. + + // It's possible to request a build of a macro, a plugin, or a test via `swift build` + // which won't have the right destination set because it's impossible to indicate it. + // + // Same happens with `--test-product` - if one of the test targets directly references + // a macro then all if its targets and the product itself become `host`. + if destination == .destination { + if let toolsProduct = findProduct(name: name, destination: .tools), + toolsProduct.type == .macro || toolsProduct.type == .plugin || toolsProduct.type == .test + { + return toolsProduct + } + } + + return nil } public func target(for name: String, destination: BuildTriple) -> ResolvedModule? { - self.allTargets.first { $0.name == name && $0.buildTriple == destination } + func findModule(name: String, destination: BuildTriple) -> ResolvedModule? { + self.allTargets.first { $0.name == name && $0.buildTriple == destination } + } + + if let module = findModule(name: name, destination: destination) { + return module + } + + // FIXME: This is a temporary workaround and needs to be handled by the callers. + + // It's possible to request a build of a macro, a plugin or a test via `swift build` + // which won't have the right destination set because it's impossible to indicate it. + // + // Same happens with `--test-product` - if one of the test targets directly references + // a macro then all if its targets and the product itself become `host`. + if destination == .destination { + if let toolsModule = findModule(name: name, destination: .tools), + toolsModule.type == .macro || toolsModule.type == .plugin || toolsModule.type == .test + { + return toolsModule + } + } + + return nil } /// All root and root dependency packages provided as input to the graph. From 4e7258455e65c470ba793020b29eff99f6c2ea74 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 7 Jun 2024 11:08:22 -0700 Subject: [PATCH 14/14] [Plugins] Fix build parameter handling during symbol graph entry point builds Supersedes https://github.com/apple/swift-package-manager/pull/7629 (cherry picked from commit 3d6473c2d491950bf6c8193cef3cd28cfed71b62) --- Sources/Commands/Utilities/PluginDelegate.swift | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Sources/Commands/Utilities/PluginDelegate.swift b/Sources/Commands/Utilities/PluginDelegate.swift index 574d1e8c265..25dc4b99853 100644 --- a/Sources/Commands/Utilities/PluginDelegate.swift +++ b/Sources/Commands/Utilities/PluginDelegate.swift @@ -389,8 +389,19 @@ final class PluginDelegate: PluginInvocationDelegate { throw StringError("could not find a target named “\(targetName)”") } + // FIXME: This is currently necessary because `target(for:destination:)` can + // produce a module that is targeting host when `targetName`` corresponds to + // a macro, plugin, or a test. Ideally we'd ask a build system for a`BuildSubset` + // and get the destination from there but there are other places that need + // refactoring in that way as well. + let buildParameters = if target.buildTriple == .tools { + try swiftCommandState.toolsBuildParameters + } else { + try swiftCommandState.productsBuildParameters + } + // Build the target, if needed. - try buildSystem.build(subset: .target(target.name)) + try buildSystem.build(subset: .target(target.name, for: buildParameters.destination)) // Configure the symbol graph extractor. var symbolGraphExtractor = try SymbolGraphExtract( @@ -419,7 +430,7 @@ final class PluginDelegate: PluginInvocationDelegate { guard let package = packageGraph.package(for: target) else { throw StringError("could not determine the package for target “\(target.name)”") } - let outputDir = try buildSystem.buildPlan.toolsBuildParameters.dataPath.appending( + let outputDir = try buildParameters.dataPath.appending( components: "extracted-symbols", package.identity.description, target.name @@ -430,7 +441,7 @@ final class PluginDelegate: PluginInvocationDelegate { let result = try symbolGraphExtractor.extractSymbolGraph( module: target, buildPlan: try buildSystem.buildPlan, - buildParameters: buildSystem.buildPlan.destinationBuildParameters, + buildParameters: buildParameters, outputRedirection: .collect, outputDirectory: outputDir, verboseOutput: self.swiftCommandState.logLevel <= .info