From be939cab20e6e98fb5734f825e88cabc5c777648 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 20 Feb 2024 20:14:54 +0000 Subject: [PATCH] Revert "Revert "Support macros when cross-compiling (#7118)" (#7352)" This reverts commit adfbd9ad4728c288b86dc0fc0ea38404a8b88a8a. --- CHANGELOG.md | 19 ++- .../Basics/Collections/IdentifiableSet.swift | 11 +- .../ClangTargetBuildDescription.swift | 9 +- .../ProductBuildDescription.swift | 4 +- .../ResolvedTarget+BuildDescription.swift | 23 +++ .../SwiftTargetBuildDescription.swift | 147 +++++++++++------- .../TargetBuildDescription.swift | 2 +- .../LLBuildManifestBuilder+Swift.swift | 36 +++-- .../LLBuildManifestBuilder.swift | 16 +- Sources/Build/BuildOperation.swift | 21 ++- .../Build/BuildPlan/BuildPlan+Product.swift | 12 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 4 +- Sources/Build/BuildPlan/BuildPlan+Test.swift | 39 +++-- Sources/Build/BuildPlan/BuildPlan.swift | 85 +++++----- Sources/Build/CMakeLists.txt | 1 + .../Commands/PackageTools/PluginCommand.swift | 12 +- Sources/Commands/SwiftTestTool.swift | 12 +- .../Commands/Utilities/PluginDelegate.swift | 2 +- .../Utilities/SymbolGraphExtract.swift | 2 +- .../Commands/Utilities/TestingSupport.swift | 20 ++- Sources/Commands/Utilities/XCTEvents.swift | 18 +-- Sources/PackageGraph/BuildTriple.swift | 23 +++ .../PackageGraph/PackageGraph+Loading.swift | 28 ++-- Sources/PackageGraph/PackageGraph.swift | 117 ++++++++++---- .../Resolution/ResolvedPackage.swift | 42 ++++- .../Resolution/ResolvedProduct.swift | 33 +++- .../Resolution/ResolvedTarget.swift | 33 +++- Sources/PackageModel/Target/Target.swift | 2 +- .../BuildParameters/BuildParameters.swift | 11 +- .../BuildSystem/BuildSystem.swift | 2 +- .../Plugins/PluginInvocation.swift | 4 +- .../SPMTestSupport/MockBuildTestHelper.swift | 42 +++-- .../SPMTestSupport/MockPackageGraphs.swift | 122 +++++++++++++++ .../SPMTestSupport/PackageGraphTester.swift | 71 ++++++++- Tests/BuildTests/BuildOperationTests.swift | 8 +- Tests/BuildTests/BuildPlanTests.swift | 113 ++++++++------ .../CrossCompilationBuildTests.swift | 86 ++++++++++ .../LLBuildManifestBuilderTests.swift | 58 +++++-- .../BuildTests/ModuleAliasingBuildTests.swift | 26 ++-- Tests/BuildTests/PluginsBuildPlanTests.swift | 26 +++- Tests/CommandsTests/PackageToolTests.swift | 47 ++++-- Tests/CommandsTests/SwiftToolTests.swift | 8 +- .../CrossCompilationPackageGraphTests.swift | 61 ++++++++ .../PackageGraphTests/PackageGraphTests.swift | 3 +- .../PluginInvocationTests.swift | 12 +- .../SourceKitLSPAPITests.swift | 29 +++- 46 files changed, 1138 insertions(+), 364 deletions(-) create mode 100644 Sources/Build/BuildDescription/ResolvedTarget+BuildDescription.swift create mode 100644 Sources/SPMTestSupport/MockPackageGraphs.swift create mode 100644 Tests/BuildTests/CrossCompilationBuildTests.swift create mode 100644 Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index fe5ed046fe5..61f95911802 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ Note: This is in reverse chronological order, so newer entries are added to the top. -Swift Next +Swift 6.0 ----------- * [#7202] @@ -8,11 +8,22 @@ Swift Next Package manifests can now access information about the Git repository the given package is in via the context object's `gitInformation` property. This allows to determine the current tag (if any), the current commit and whether or not there are uncommited changes. +* [#7201] + + `// 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. @@ -387,4 +398,8 @@ Swift 3.0 [#6276]: /~https://github.com/apple/swift-package-manager/pull/6276 [#6540]: /~https://github.com/apple/swift-package-manager/pull/6540 [#6663]: /~https://github.com/apple/swift-package-manager/pull/6663 +[#7010]: /~https://github.com/apple/swift-package-manager/pull/7010 [#7101]: /~https://github.com/apple/swift-package-manager/pull/7101 +[#7118]: /~https://github.com/apple/swift-package-manager/pull/7118 +[#7201]: /~https://github.com/apple/swift-package-manager/pull/7201 +[#7202]: /~https://github.com/apple/swift-package-manager/pull/7202 diff --git a/Sources/Basics/Collections/IdentifiableSet.swift b/Sources/Basics/Collections/IdentifiableSet.swift index b3bfec3071f..59bda6bdd85 100644 --- a/Sources/Basics/Collections/IdentifiableSet.swift +++ b/Sources/Basics/Collections/IdentifiableSet.swift @@ -45,13 +45,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.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 69412b64fb3..cd37cd23cd1 100644 --- a/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/ClangTargetBuildDescription.swift @@ -19,6 +19,9 @@ import struct SPMBuildCore.BuildParameters import struct SPMBuildCore.BuildToolPluginInvocationResult import struct SPMBuildCore.PrebuildCommandResult +@_spi(SwiftPMInternal) +import SPMBuildCore + import enum TSCBasic.ProcessEnv /// Target description for a Clang target i.e. C language family target. @@ -49,7 +52,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 } @@ -127,7 +130,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. @@ -219,7 +222,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 bb96cd383a2..d5e0e9ba8f9 100644 --- a/Sources/Build/BuildDescription/ProductBuildDescription.swift +++ b/Sources/Build/BuildDescription/ProductBuildDescription.swift @@ -311,7 +311,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 @@ -346,7 +346,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/ResolvedTarget+BuildDescription.swift b/Sources/Build/BuildDescription/ResolvedTarget+BuildDescription.swift new file mode 100644 index 00000000000..10024bd0d10 --- /dev/null +++ b/Sources/Build/BuildDescription/ResolvedTarget+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.ResolvedTarget + +@_spi(SwiftPMInternal) +import SPMBuildCore + +extension ResolvedTarget { + func tempsPath(_ buildParameters: BuildParameters) -> AbsolutePath { + buildParameters.buildPath.appending(component: self.c99name + "\(self.buildTriple.suffix).build") + } +} diff --git a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift index a7216c99aa0..0bf30b71294 100644 --- a/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift @@ -15,6 +15,8 @@ import Foundation import PackageGraph import PackageLoading import PackageModel + +@_spi(SwiftPMInternal) import SPMBuildCore #if USE_IMPL_ONLY_IMPORTS @@ -40,8 +42,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 @@ -60,7 +65,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 } @@ -95,7 +100,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( @@ -106,16 +111,16 @@ public final class SwiftTargetBuildDescription { } var modulesPath: AbsolutePath { - return self.buildParameters.buildPath.appending(component: "Modules") + return self.defaultBuildParameters.buildPath.appending(component: "Modules\(self.target.buildTriple.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 @@ -125,7 +130,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") } @@ -241,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( @@ -249,13 +254,14 @@ public final class SwiftTargetBuildDescription { target: ResolvedTarget, 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 { @@ -267,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 @@ -277,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 @@ -291,7 +299,7 @@ public final class SwiftTargetBuildDescription { target: target, toolsVersion: toolsVersion, additionalFileRules: additionalFileRules, - buildParameters: buildParameters, + buildParameters: destinationBuildParameters, buildToolPluginInvocationResults: buildToolPluginInvocationResults, prebuildCommandResults: prebuildCommandResults, observabilityScope: observabilityScope @@ -328,18 +336,22 @@ 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) try self.fileSystem.writeIfChanged(path: path, string: content) } - // FIXME: This will not work well for large files, as we will store the entire contents, plus its byte array representation in memory and also `writeIfChanged()` will read the entire generated file again. + // FIXME: This will not work well for large files, as we will store the entire contents, plus its byte array + // representation in memory and also `writeIfChanged()` will read the entire generated file again. private func generateResourceEmbeddingCode() throws { guard needsResourceEmbedding else { return } @@ -372,7 +384,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 @@ -422,7 +434,11 @@ public final class SwiftTargetBuildDescription { private func packageNameArgumentIfSupported(with pkg: ResolvedPackage, packageAccess: Bool) -> [String] { let flag = "-package-name" if pkg.manifest.usePackageNameFlag, - DriverSupport.checkToolchainDriverFlags(flags: [flag], toolchain: self.buildParameters.toolchain, fileSystem: self.fileSystem) { + DriverSupport.checkToolchainDriverFlags( + flags: [flag], + toolchain: self.defaultBuildParameters.toolchain, + fileSystem: self.fileSystem + ) { if packageAccess { let pkgID = pkg.identity.description.spm_mangledToC99ExtendedIdentifier() return [flag, pkgID] @@ -436,12 +452,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 @@ -450,7 +466,14 @@ public final class SwiftTargetBuildDescription { #endif // If we're using an OSS toolchain, add the required arguments bringing in the plugin server from the default toolchain if available. - if self.buildParameters.toolchain.isSwiftDevelopmentToolchain, DriverSupport.checkSupportedFrontendFlags(flags: ["-external-plugin-path"], toolchain: self.buildParameters.toolchain, fileSystem: self.fileSystem), let pluginServer = try self.buildParameters.toolchain.swiftPluginServerPath { + if self.defaultBuildParameters.toolchain.isSwiftDevelopmentToolchain, + DriverSupport.checkSupportedFrontendFlags( + flags: ["-external-plugin-path"], + toolchain: self.defaultBuildParameters.toolchain, + fileSystem: self.fileSystem + ), + let pluginServer = try self.defaultBuildParameters.toolchain.swiftPluginServerPath + { let toolchainUsrPath = pluginServer.parentDirectory.parentDirectory let pluginPathComponents = ["lib", "swift", "host", "plugins"] @@ -461,8 +484,12 @@ public final class SwiftTargetBuildDescription { args += ["-Xfrontend", "-external-plugin-path", "-Xfrontend", "\(localPluginPath)#\(pluginServer.pathString)"] } - 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 { @@ -479,11 +506,11 @@ 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) args += ["-swift-version", self.swiftVersion.rawValue] // pass `-v` during verbose builds. - if self.buildParameters.outputParameters.isVerbose { + if self.defaultBuildParameters.outputParameters.isVerbose { args += ["-v"] } @@ -491,22 +518,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 @@ -526,8 +553,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"] } @@ -540,7 +567,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. @@ -549,12 +576,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"] } @@ -564,7 +591,7 @@ public final class SwiftTargetBuildDescription { switch testTargetRole { case .discovery: 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] @@ -584,17 +611,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. @@ -603,7 +630,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: @@ -613,7 +640,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] } @@ -637,7 +664,7 @@ public final class SwiftTargetBuildDescription { // 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 { @@ -652,7 +679,7 @@ 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) @@ -670,7 +697,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)) @@ -690,7 +717,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 { @@ -704,7 +731,7 @@ public final class SwiftTargetBuildDescription { """# - if self.buildParameters.useWholeModuleOptimization { + if self.defaultBuildParameters.useWholeModuleOptimization { let moduleName = self.target.c99name content += #""" @@ -735,7 +762,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] = [] // Swift defines. @@ -838,7 +865,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 @@ -849,7 +876,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: @@ -861,7 +888,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: @@ -875,7 +902,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 [] @@ -885,20 +912,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 4fae9198680..ad9de913c2d 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+Swift.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift index a51bf24d954..116467633e5 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: [ResolvedTarget.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 ResolvedTarget.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(config: target.defaultBuildParameters.buildConfig) 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 @@ -450,7 +452,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) @@ -477,7 +479,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 { @@ -489,7 +491,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(config: target.defaultBuildParameters.buildConfig))) } return inputs + additionalInputs @@ -498,7 +500,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(config: target.defaultBuildParameters.buildConfig) let targetOutput: Node = .virtual(targetName) self.manifest.addNode(targetOutput, toTarget: targetName) @@ -507,7 +509,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) } @@ -517,13 +519,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 4d9b6d62787..63038ce6a8a 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -14,6 +14,8 @@ import Basics import LLBuildManifest import PackageGraph import PackageModel + +@_spi(SwiftPMInternal) import SPMBuildCore #if USE_IMPL_ONLY_IMPORTS @@ -322,26 +324,26 @@ extension ResolvedTarget { } public func getLLBuildTargetName(config: String) -> String { - "\(name)-\(config).module" + "\(self.name)-\(config)\(self.buildTriple.suffix).module" } public func getLLBuildResourcesCmdName(config: String) -> String { - "\(name)-\(config).module-resources" + "\(self.name)-\(config).module-resources" } } extension ResolvedProduct { public func getLLBuildTargetName(config: String) throws -> String { - let potentialExecutableTargetName = "\(name)-\(config).exe" - let potentialLibraryTargetName = "\(name)-\(config).dylib" + let potentialExecutableTargetName = "\(name)-\(config)\(self.buildTriple.suffix).exe" + let potentialLibraryTargetName = "\(name)-\(config)\(self.buildTriple.suffix).dylib" switch type { case .library(.dynamic): return potentialLibraryTargetName case .test: - return "\(name)-\(config).test" + return "\(name)-\(config)\(self.buildTriple.suffix).test" case .library(.static): - return "\(name)-\(config).a" + return "\(name)-\(config)\(self.buildTriple.suffix).a" case .library(.automatic): throw InternalError("automatic library not supported") case .executable, .snippet: @@ -358,7 +360,7 @@ extension ResolvedProduct { } public func getCommandName(config: String) throws -> String { - try "C." + self.getLLBuildTargetName(config: config) + try "C.\(self.getLLBuildTargetName(config: config))\(self.buildTriple.suffix)" } } diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index fab2429cccf..d661ea9fdd5 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -13,7 +13,10 @@ @_spi(SwiftPMInternal) import Basics import LLBuildManifest + +@_spi(SwiftPMInternal) import PackageGraph + import PackageLoading import PackageModel import SPMBuildCore @@ -269,7 +272,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 +298,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]() } @@ -538,17 +543,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 +566,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 +584,6 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } } - // Surface any diagnostics from build tool plugins. var succeeded = true for (_, (target, results)) in buildToolPluginInvocationResults { @@ -656,7 +663,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, diff --git a/Sources/Build/BuildPlan/BuildPlan+Product.swift b/Sources/Build/BuildPlan/BuildPlan+Product.swift index d14ec2418ad..a0442686232 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Product.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Product.swift @@ -70,7 +70,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)") } @@ -92,13 +92,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 @@ -220,9 +220,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 93fd9da29c7..9d11d012d6e 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: PackageGraph, - _ 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: ResolvedTarget, 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] = [] @@ -96,9 +97,10 @@ extension BuildPlan { package: package, target: discoveryResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: destinationBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .discovery, - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -112,8 +114,8 @@ extension BuildPlan { swiftTargetDependencies: [Target.Dependency], resolvedTargetDependencies: [ResolvedTarget.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) @@ -136,9 +138,10 @@ extension BuildPlan { package: package, target: entryPointResolvedTarget, toolsVersion: toolsVersion, - buildParameters: buildParameters, + destinationBuildParameters: destinationBuildParameters, + toolsBuildParameters: toolsBuildParameters, testTargetRole: .entryPoint(isSynthesized: true), - disableSandbox: disableSandbox, + shouldDisableSandbox: shouldDisableSandbox, fileSystem: fileSystem, observabilityScope: observabilityScope ) @@ -148,7 +151,7 @@ extension BuildPlan { let swiftTargetDependencies: [Target.Dependency] let resolvedTargetDependencies: [ResolvedTarget.Dependency] - switch buildParameters.testingParameters.library { + switch destinationBuildParameters.testingParameters.library { case .xctest: discoveryTargets = try generateDiscoveryTargets() swiftTargetDependencies = [.target(discoveryTargets!.target, conditions: [])] @@ -181,9 +184,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 +207,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 1f4eda79e5f..2c4c7519fd8 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -127,13 +127,13 @@ extension BuildParameters { return [] } - /// Computes the target triple arguments for a given resolved target. - public func targetTripleArgs(for target: ResolvedTarget) throws -> [String] { + public func tripleArgs(for target: ResolvedTarget) 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 { @@ -158,7 +158,7 @@ extension BuildParameters { /// Returns the scoped view of build settings for a given target. func createScope(for target: ResolvedTarget) -> BuildSettings.Scope { - return BuildSettings.Scope(target.underlying.buildSettings, environment: buildEnvironment) + BuildSettings.Scope(target.underlying.buildSettings, environment: buildEnvironment) } } @@ -185,16 +185,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: ResolvedTarget) -> 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: PackageGraph @@ -231,14 +221,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,7 +236,7 @@ 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: PackageGraph, @@ -257,7 +247,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { observabilityScope: ObservabilityScope ) throws { try self.init( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, additionalFileRules: additionalFileRules, @@ -268,11 +258,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: PackageGraph, + 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: PackageGraph, additionalFileRules: [FileRuleDescription] = [], buildToolPluginInvocationResults: [ResolvedTarget.ID: [BuildToolPluginInvocationResult]] = [:], prebuildCommandResults: [ResolvedTarget.ID: [PrebuildCommandResult]] = [:], @@ -280,16 +288,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 +306,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 +344,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 +393,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 ) @@ -436,18 +446,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) @@ -553,9 +566,9 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } // Add search paths from the system library targets. - for target in graph.reachableTargets { + for target in self.graph.reachableTargets { if let systemLib = target.underlying as? SystemLibraryTarget { - arguments.append(contentsOf: try self.pkgConfig(for: systemLib).cFlags) + try arguments.append(contentsOf: self.pkgConfig(for: systemLib).cFlags) // Add the path to the module map. arguments += ["-I", systemLib.moduleMapPath.parentDirectory.pathString] } @@ -590,7 +603,7 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } // Add search paths from the system library targets. - for target in graph.reachableTargets { + for target in self.graph.reachableTargets { if let systemLib = target.underlying as? SystemLibraryTarget { arguments += try self.pkgConfig(for: systemLib).cFlags } @@ -729,7 +742,7 @@ extension ResolvedProduct { } private var isBinaryOnly: Bool { - return self.targets.filter({ !($0.underlying is BinaryTarget) }).isEmpty + self.targets.filter { !($0.underlying is BinaryTarget) }.isEmpty } private var isPlugin: Bool { diff --git a/Sources/Build/CMakeLists.txt b/Sources/Build/CMakeLists.txt index fcc51aed76d..d978c3ff53a 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/ResolvedTarget+BuildDescription.swift BuildDescription/SwiftTargetBuildDescription.swift BuildDescription/TargetBuildDescription.swift BuildManifest/LLBuildManifestBuilder.swift diff --git a/Sources/Commands/PackageTools/PluginCommand.swift b/Sources/Commands/PackageTools/PluginCommand.swift index 1968dae8183..c90553d7b1c 100644 --- a/Sources/Commands/PackageTools/PluginCommand.swift +++ b/Sources/Commands/PackageTools/PluginCommand.swift @@ -14,7 +14,10 @@ import ArgumentParser import Basics import CoreCommands import Dispatch + +@_spi(SwiftPMInternal) import PackageGraph + import PackageModel import enum TSCBasic.ProcessEnv @@ -315,6 +318,9 @@ struct PluginCommand: SwiftCommand { let toolSearchDirs = [try swiftTool.getTargetToolchain().swiftCompilerPath.parentDirectory] + getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: .none) + var buildToolsGraph = packageGraph + try buildToolsGraph.updateBuildTripleRecursively(.tools) + let buildParameters = try swiftTool.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 swiftTool.createBuildSystem( @@ -323,10 +329,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: swiftTool.fileSystem, environment: buildParameters.buildEnvironment, for: try pluginScriptRunner.hostTriple diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index 1a713702f43..63e8fde2305 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -421,7 +421,7 @@ public struct SwiftTestTool: SwiftCommand { let toolchain = try swiftTool.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - buildParameters: buildParameters, + destinationBuildParameters: buildParameters, sanitizers: globalOptions.build.sanitizers ) @@ -662,13 +662,17 @@ extension SwiftTestTool { // MARK: - swift-testing private func swiftTestingRun(_ swiftTool: SwiftTool) throws { - let buildParameters = try swiftTool.buildParametersForTest(enableCodeCoverage: false, shouldSkipBuilding: sharedOptions.shouldSkipBuilding, library: .swiftTesting) + let buildParameters = try swiftTool.buildParametersForTest( + enableCodeCoverage: false, + shouldSkipBuilding: sharedOptions.shouldSkipBuilding, + library: .swiftTesting + ) let testProducts = try buildTestsIfNeeded(swiftTool: swiftTool, buildParameters: buildParameters) let toolchain = try swiftTool.getTargetToolchain() let testEnv = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - buildParameters: buildParameters, + destinationBuildParameters: buildParameters, sanitizers: globalOptions.build.sanitizers ) @@ -970,7 +974,7 @@ final class ParallelTestRunner { let testEnv = try TestingSupport.constructTestEnvironment( toolchain: self.toolchain, - buildParameters: self.buildParameters, + destinationBuildParameters: self.buildParameters, sanitizers: self.buildOptions.sanitizers ) diff --git a/Sources/Commands/Utilities/PluginDelegate.swift b/Sources/Commands/Utilities/PluginDelegate.swift index d4ad1554444..ec1257fcece 100644 --- a/Sources/Commands/Utilities/PluginDelegate.swift +++ b/Sources/Commands/Utilities/PluginDelegate.swift @@ -235,7 +235,7 @@ final class PluginDelegate: PluginInvocationDelegate { // Construct the environment we'll pass down to the tests. let testEnvironment = try TestingSupport.constructTestEnvironment( toolchain: toolchain, - buildParameters: toolsBuildParameters, + destinationBuildParameters: toolsBuildParameters, sanitizers: swiftTool.options.build.sanitizers ) diff --git a/Sources/Commands/Utilities/SymbolGraphExtract.swift b/Sources/Commands/Utilities/SymbolGraphExtract.swift index f9423384c9b..7bdb96dd907 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", target.c99name] - commandLine += try buildParameters.targetTripleArgs(for: target) + commandLine += try buildParameters.tripleArgs(for: target) 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 236feaa072e..7556a3e0c56 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 swiftTool.fileSystem.isFile(maybePath) { return maybePath } else { @@ -46,7 +48,10 @@ enum TestingSupport { } if let firstCLIArgument = CommandLine.arguments.first { - let runningSwiftBuildPath = try AbsolutePath(validating: firstCLIArgument, relativeTo: swiftTool.originalWorkingDirectory) + let runningSwiftBuildPath = try AbsolutePath( + validating: firstCLIArgument, + relativeTo: swiftTool.originalWorkingDirectory + ) if let xctestHelperPath = findXCTestHelper(swiftBuildPath: runningSwiftBuildPath) { return xctestHelperPath } @@ -54,7 +59,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 } @@ -110,7 +118,7 @@ enum TestingSupport { args = [try Self.xctestHelperPath(swiftTool: swiftTool).pathString, path.pathString, tempFile.path.pathString] let env = try Self.constructTestEnvironment( toolchain: try swiftTool.getTargetToolchain(), - buildParameters: swiftTool.buildParametersForTest( + destinationBuildParameters: swiftTool.buildParametersForTest( enableCodeCoverage: enableCodeCoverage, shouldSkipBuilding: shouldSkipBuilding, experimentalTestOutput: experimentalTestOutput, @@ -126,7 +134,7 @@ enum TestingSupport { #else let env = try Self.constructTestEnvironment( toolchain: try swiftTool.getTargetToolchain(), - buildParameters: swiftTool.buildParametersForTest( + destinationBuildParameters: swiftTool.buildParametersForTest( enableCodeCoverage: enableCodeCoverage, shouldSkipBuilding: shouldSkipBuilding, library: .xctest @@ -143,7 +151,7 @@ enum TestingSupport { /// Creates the environment needed to test related tools. static func constructTestEnvironment( toolchain: UserToolchain, - buildParameters: BuildParameters, + destinationBuildParameters buildParameters: BuildParameters, sanitizers: [Sanitizer] ) throws -> EnvironmentVariables { var env = EnvironmentVariables.process() 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/PackageGraph+Loading.swift b/Sources/PackageGraph/PackageGraph+Loading.swift index 420e1ccce67..2c456468f1d 100644 --- a/Sources/PackageGraph/PackageGraph+Loading.swift +++ b/Sources/PackageGraph/PackageGraph+Loading.swift @@ -165,12 +165,12 @@ extension PackageGraph { observabilityScope: observabilityScope ) - let rootPackages = resolvedPackages.filter{ root.manifests.values.contains($0.manifest) } + let rootPackages = resolvedPackages.filter { root.manifests.values.contains($0.manifest) } checkAllDependenciesAreUsed(rootPackages, observabilityScope: observabilityScope) return try PackageGraph( rootPackages: rootPackages, - rootDependencies: resolvedPackages.filter{ rootDependencies.contains($0.manifest) }, + rootDependencies: resolvedPackages.filter { rootDependencies.contains($0.manifest) }, dependencies: requiredDependencies, binaryArtifacts: binaryArtifacts ) @@ -180,16 +180,16 @@ extension PackageGraph { private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], observabilityScope: ObservabilityScope) { 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 dependency in package.dependencies { // We continue if the dependency contains executable products to make sure we don't @@ -217,7 +217,12 @@ private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], obse ) // 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)) } @@ -275,7 +280,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 { @@ -627,12 +635,12 @@ private func createResolvedPackages( observabilityScope.emit( ModuleError.duplicateModule( targetName: entry.key, - packages: entry.value.map{ $0.identity }) + packages: entry.value.map { $0.identity }) ) } } - return try packageBuilders.map{ try $0.construct() } + return try packageBuilders.map { try $0.construct() } } private func emitDuplicateProductDiagnostic( diff --git a/Sources/PackageGraph/PackageGraph.swift b/Sources/PackageGraph/PackageGraph.swift index bd3446b0499..8a5e8c7426d 100644 --- a/Sources/PackageGraph/PackageGraph.swift +++ b/Sources/PackageGraph/PackageGraph.swift @@ -59,17 +59,16 @@ public struct PackageGraph { public let packages: [ResolvedPackage] /// 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 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. /// @@ -80,10 +79,14 @@ public struct PackageGraph { /// Returns true if a given target is present in root packages and is not excluded for the given build environment. public func isInRootPackages(_ target: ResolvedTarget, 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: ResolvedTarget.Dependency) -> ResolvedTarget? in + let unsatisfiedDependencyTargets = unsatisfiedDependencies.compactMap { ( + dep: ResolvedTarget.Dependency + ) -> ResolvedTarget? in switch dep { case .target(let target, _): return target @@ -101,14 +104,14 @@ public struct PackageGraph { return self.rootPackages.contains(id: package.id) } - private let targetsToPackages: [ResolvedTarget.ID: ResolvedPackage] + private var targetsToPackages: [ResolvedTarget.ID: ResolvedPackage] /// Returns the package that contains the target, or nil if the target isn't in the graph. public func package(for target: ResolvedTarget) -> ResolvedPackage? { return self.targetsToPackages[target.id] } - private let productsToPackages: [ResolvedProduct.ID: ResolvedPackage] + private var productsToPackages: [ResolvedProduct.ID: ResolvedPackage] /// Returns the package that contains the product, or nil if the product isn't in the graph. public func package(for product: ResolvedProduct) -> ResolvedPackage? { return self.productsToPackages[product.id] @@ -132,44 +135,68 @@ public struct PackageGraph { self.inputPackages = rootPackages + rootDependencies self.binaryArtifacts = binaryArtifacts self.packages = try topologicalSort(inputPackages, successors: { $0.dependencies }) + let identitiesToPackages = self.packages.spm_createDictionary { ($0.identity, $0) } // Create a mapping from targets to the packages that define them. Here // we include all targets, including tests in non-root packages, since // this is intended for lookup and not traversal. - self.targetsToPackages = packages.reduce(into: [:], { partial, package in - package.targets.forEach{ partial[$0.id] = package } + var targetsToPackages = self.packages.reduce(into: [:], { partial, package in + package.targets.forEach { partial[$0.id] = package } + }) + + // Create a mapping from products to the packages that define them. Here + // we include all products, including tests in non-root packages, since + // this is intended for lookup and not traversal. + var productsToPackages = packages.reduce(into: [:], { partial, package in + package.products.forEach { partial[$0.id] = package } }) - let allTargets = IdentifiableSet(packages.flatMap({ package -> [ResolvedTarget] in + var allTargets = IdentifiableSet() + var allProducts = IdentifiableSet() + for package in self.packages { + let targetsToInclude: [ResolvedTarget] 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 } } - })) - // Create a mapping from products to the packages that define them. Here - // we include all products, including tests in non-root packages, since - // this is intended for lookup and not traversal. - self.productsToPackages = packages.reduce(into: [:], { partial, package in - package.products.forEach { partial[$0.id] = package } - }) + 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) + targetsToPackages[targetDependency.id] = package + case .product(let productDependency, _): + allProducts.insert(productDependency) + productsToPackages[productDependency.id] = + identitiesToPackages[productDependency.packageIdentity] + } + } + } + } - 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 // try to run them. - return package.products.filter({ $0.type != .test }) + allProducts.formUnion(package.products.filter { $0.type != .test }) } - })) + } + + self.targetsToPackages = targetsToPackages + self.productsToPackages = productsToPackages // 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 }) @@ -179,6 +206,42 @@ public struct PackageGraph { self.allProducts = allProducts } + @_spi(SwiftPMInternal) + public 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 + }) + + self.targetsToPackages = .init(self.targetsToPackages.map { + var target = $0 + target.buildTriple = buildTriple + return (target, $1) + }, uniquingKeysWith: { $1 }) + self.productsToPackages = .init(self.productsToPackages.map { + var product = $0 + product.buildTriple = buildTriple + return (product, $1) + }, uniquingKeysWith: { $1 }) + } + /// Computes a map from each executable target in any of the root packages to the corresponding test targets. func computeTestTargetsForExecutableTargets() throws -> [ResolvedTarget.ID: [ResolvedTarget]] { var result = [ResolvedTarget.ID: [ResolvedTarget]]() diff --git a/Sources/PackageGraph/Resolution/ResolvedPackage.swift b/Sources/PackageGraph/Resolution/ResolvedPackage.swift index bf8d81eac78..e745696036a 100644 --- a/Sources/PackageGraph/Resolution/ResolvedPackage.swift +++ b/Sources/PackageGraph/Resolution/ResolvedPackage.swift @@ -11,6 +11,9 @@ //===----------------------------------------------------------------------===// import Basics + +import struct OrderedCollections.OrderedDictionary + import PackageModel /// A fully resolved package. Contains resolved targets, products and dependencies of the package. @@ -64,8 +67,43 @@ public struct ResolvedPackage { platformVersionProvider: PlatformVersionProvider ) { self.underlying = underlying - self.targets = targets - self.products = products + + var processedTargets = OrderedDictionary( + uniqueKeysWithValues: targets.map { ($0.id, $0) } + ) + var processedProducts = [ResolvedProduct]() + // Make sure that direct macro dependencies of test products are also built for the target triple. + // Without this workaround, `assertMacroExpansion` in tests can't be built, as it requires macros + // and SwiftSyntax to be built for the target triple: /~https://github.com/apple/swift-package-manager/pull/7349 + for var product in products { + if product.type == .test { + var targets = IdentifiableSet() + for var target in product.targets { + var dependencies = [ResolvedTarget.Dependency]() + for dependency in target.dependencies { + switch dependency { + case .target(var target, let conditions) where target.type == .macro: + target.buildTriple = .destination + dependencies.append(.target(target, conditions: conditions)) + processedTargets[target.id] = target + case .product(var product, let conditions) where product.type == .macro: + product.buildTriple = .destination + dependencies.append(.product(product, conditions: conditions)) + default: + dependencies.append(dependency) + } + } + target.dependencies = dependencies + targets.insert(target) + } + product.targets = targets + } + + processedProducts.append(product) + } + + self.products = processedProducts + self.targets = Array(processedTargets.values) self.dependencies = dependencies self.defaultLocalization = defaultLocalization self.supportedPlatforms = supportedPlatforms diff --git a/Sources/PackageGraph/Resolution/ResolvedProduct.swift b/Sources/PackageGraph/Resolution/ResolvedProduct.swift index 1208b5b0d7f..c63e86bfabe 100644 --- a/Sources/PackageGraph/Resolution/ResolvedProduct.swift +++ b/Sources/PackageGraph/Resolution/ResolvedProduct.swift @@ -30,7 +30,7 @@ public struct ResolvedProduct { public let underlying: Product /// The top level targets contained in this product. - public let targets: IdentifiableSet + public internal(set) var targets: IdentifiableSet /// Executable target for test entry point file. public let testEntryPointTarget: ResolvedTarget? @@ -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,18 @@ public struct ResolvedProduct { ) } - self.buildTriple = .destination + self.buildTriple = product.buildTriple + self.updateBuildTriplesOfDependencies() + } + + private mutating func updateBuildTriplesOfDependencies() { + if case .tools = self.buildTriple { + self.targets = IdentifiableSet(self.targets.map { + var target = $0 + target.buildTriple = .tools + return target + }) + } } /// True if this product contains Swift targets. @@ -166,13 +185,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/PackageGraph/Resolution/ResolvedTarget.swift b/Sources/PackageGraph/Resolution/ResolvedTarget.swift index 4e9fecaf804..69864b21e22 100644 --- a/Sources/PackageGraph/Resolution/ResolvedTarget.swift +++ b/Sources/PackageGraph/Resolution/ResolvedTarget.swift @@ -133,7 +133,7 @@ public struct ResolvedTarget { 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? @@ -144,7 +144,11 @@ public struct ResolvedTarget { private let platformVersionProvider: PlatformVersionProvider /// Triple for which this resolved target should be compiled for. - public let buildTriple: BuildTriple + public internal (set) var buildTriple: BuildTriple { + didSet { + self.updateBuildTriplesOfDependencies() + } + } /// Create a resolved target instance. public init( @@ -161,7 +165,26 @@ public struct ResolvedTarget { self.defaultLocalization = defaultLocalization self.supportedPlatforms = supportedPlatforms self.platformVersionProvider = platformVersionProvider - self.buildTriple = .destination + self.buildTriple = underlying.buildTriple + self.updateBuildTriplesOfDependencies() + } + + private mutating func updateBuildTriplesOfDependencies() { + if case .tools = self.buildTriple { + for (i, dependency) in dependencies.enumerated() { + let updatedDependency: Dependency + switch dependency { + case .target(var target, let conditions): + target.buildTriple = .tools + updatedDependency = .target(target, conditions: conditions) + case .product(var product, let conditions): + product.buildTriple = .tools + updatedDependency = .product(product, conditions: conditions) + } + + dependencies[i] = updatedDependency + } + } } public func getSupportedPlatform(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform { @@ -175,7 +198,7 @@ public struct ResolvedTarget { extension ResolvedTarget: CustomStringConvertible { public var description: String { - return "" + return "" } } @@ -244,7 +267,7 @@ extension ResolvedTarget: Identifiable { public struct ID: Hashable { public let targetName: String let packageIdentity: PackageIdentity - public let buildTriple: BuildTriple + public var buildTriple: BuildTriple } public var id: ID { diff --git a/Sources/PackageModel/Target/Target.swift b/Sources/PackageModel/Target/Target.swift index 541e37794de..411415a719f 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 cbc5cb5499c..6e4ceb04aa2 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)\(product.buildTriple.suffix)\(self.triple.executableExtension)") switch product.type { case .executable, .snippet: @@ -329,3 +329,12 @@ extension Triple { return !self.isWindows() } } + +extension BuildTriple { + /// 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. + @_spi(SwiftPMInternal) + public var suffix: String { + if self == .tools { "-tool" } else { "" } + } +} diff --git a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift index e8d1fd3efe1..5d9e1e0e982 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/PluginInvocation.swift b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift index 72dcef42431..f948995f7e6 100644 --- a/Sources/SPMBuildCore/Plugins/PluginInvocation.swift +++ b/Sources/SPMBuildCore/Plugins/PluginInvocation.swift @@ -592,7 +592,9 @@ extension PackageGraph { } // 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 } diff --git a/Sources/SPMTestSupport/MockBuildTestHelper.swift b/Sources/SPMTestSupport/MockBuildTestHelper.swift index 2aeb77764ff..58297fdd979 100644 --- a/Sources/SPMTestSupport/MockBuildTestHelper.swift +++ b/Sources/SPMTestSupport/MockBuildTestHelper.swift @@ -15,6 +15,8 @@ import Basics @_spi(SwiftPMInternal) import Build +import struct PackageGraph.ResolvedTarget +import struct PackageGraph.ResolvedProduct import PackageModel import SPMBuildCore import TSCUtility @@ -73,14 +75,14 @@ public let defaultTargetTriple: String = hostTriple.tripleString #endif public func mockBuildParameters( - buildPath: AbsolutePath = "/path/to/build", + 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, @@ -88,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 ), @@ -129,7 +131,7 @@ 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 { @@ -138,15 +140,15 @@ enum BuildError: Swift.Error { public struct BuildPlanResult { public let plan: Build.BuildPlan - public let targetMap: [String: TargetBuildDescription] - public let productMap: [String: Build.ProductBuildDescription] + public let targetMap: [ResolvedTarget.ID: TargetBuildDescription] + public 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 { @@ -156,7 +158,7 @@ public struct BuildPlanResult { else { throw BuildError.error("Target \($0) not found.") } - return (target.name, $1) + return (target.id, $1) } ) } @@ -170,16 +172,26 @@ public struct BuildPlanResult { } public func target(for name: String) throws -> TargetBuildDescription { - guard let target = targetMap[name] else { - throw BuildError.error("Target \(name) not found.") + 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.") + 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 new file mode 100644 index 00000000000..b84b897a257 --- /dev/null +++ b/Sources/SPMTestSupport/MockPackageGraphs.swift @@ -0,0 +1,122 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import class Basics.ObservabilitySystem +import class Basics.ObservabilityScope +import struct PackageGraph.PackageGraph +import class PackageModel.Manifest +import struct PackageModel.ProductDescription +import struct PackageModel.TargetDescription +import protocol TSCBasic.FileSystem +import class TSCBasic.InMemoryFileSystem + +public func macrosPackageGraph() throws -> ( + graph: PackageGraph, + fileSystem: FileSystem, + observabilityScope: ObservabilityScope +) { + let fs = InMemoryFileSystem(emptyFiles: + "/swift-firmware/Sources/Core/source.swift", + "/swift-firmware/Sources/HAL/source.swift", + "/swift-firmware/Tests/CoreTests/source.swift", + "/swift-firmware/Tests/HALTests/source.swift", + "/swift-mmio/Sources/MMIO/source.swift", + "/swift-mmio/Sources/MMIOMacros/source.swift", + "/swift-syntax/Sources/SwiftSyntax/source.swift", + "/swift-syntax/Tests/SwiftSyntaxTests/source.swift" + ) + + let observability = ObservabilitySystem.makeForTesting() + let graph = try loadPackageGraph( + fileSystem: fs, + manifests: [ + Manifest.createRootManifest( + displayName: "swift-firmware", + path: "/swift-firmware", + dependencies: [ + .localSourceControl( + path: "/swift-mmio", + requirement: .upToNextMajor(from: "1.0.0") + ) + ], + products: [ + ProductDescription( + name: "Core", + type: .executable, + targets: ["Core"] + ) + ], + targets: [ + TargetDescription( + name: "Core", + dependencies: ["HAL"], + type: .executable + ), + TargetDescription( + name: "HAL", + dependencies: [.product(name: "MMIO", package: "swift-mmio")] + ), + TargetDescription(name: "CoreTests", dependencies: ["Core"], type: .test), + TargetDescription(name: "HALTests", dependencies: ["HAL"], type: .test), + ] + ), + Manifest.createFileSystemManifest( + 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: "SwiftSyntax", package: "swift-syntax")], + type: .macro + ) + ] + ), + Manifest.createFileSystemManifest( + displayName: "swift-syntax", + path: "/swift-syntax", + products: [ + ProductDescription( + name: "SwiftSyntax", + type: .library(.automatic), + targets: ["SwiftSyntax"] + ) + ], + targets: [ + TargetDescription(name: "SwiftSyntax", dependencies: []), + TargetDescription(name: "SwiftSyntaxTests", dependencies: ["SwiftSyntax"], type: .test), + ] + ), + ], + observabilityScope: observability.topScope + ) + + XCTAssertNoDiagnostics(observability.diagnostics) + + return (graph, fs, observability.topScope) +} diff --git a/Sources/SPMTestSupport/PackageGraphTester.swift b/Sources/SPMTestSupport/PackageGraphTester.swift index fc4d3c231b5..91d2d61d8e3 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 @@ -98,6 +98,15 @@ public final class PackageGraphResult { body(ResolvedTargetResult(target)) } + public func checkTargets( + _ name: String, + file: StaticString = #file, + line: UInt = #line, + body: ([ResolvedTargetResult]) -> Void + ) { + body(graph.allTargets.filter { $0.name == name }.map(ResolvedTargetResult.init)) + } + public func checkProduct( _ name: String, file: StaticString = #file, @@ -149,7 +158,7 @@ public final class PackageGraphResult { } public final class ResolvedTargetResult { - private let target: ResolvedTarget + let target: ResolvedTarget init(_ target: ResolvedTarget) { self.target = target @@ -176,7 +185,9 @@ public final class ResolvedTargetResult { } 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) })) + let targetPlatforms = Dictionary( + uniqueKeysWithValues: target.supportedPlatforms.map { ($0.platform.name, $0.version.versionString) } + ) XCTAssertEqual(platforms, targetPlatforms, file: file, line: line) } @@ -187,16 +198,24 @@ 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) + public 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 { @@ -217,6 +236,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,6 +293,22 @@ 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) + } + + public 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 { 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 2055e433f4b..5ea4e286dac 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -47,7 +47,7 @@ extension Build.BuildPlan { observabilityScope: ObservabilityScope ) throws { try self.init( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, additionalFileRules: additionalFileRules, @@ -888,7 +888,7 @@ final class BuildPlanTests: XCTestCase { buildPath: buildDirPath, config: .release, toolchain: UserToolchain.default, - targetTriple: UserToolchain.default.targetTriple, + triple: UserToolchain.default.targetTriple, useExplicitModuleBuild: true ), graph: graph, @@ -1118,11 +1118,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", @@ -1469,7 +1469,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"), @@ -1712,8 +1718,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 @@ -1784,7 +1791,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) @@ -1840,8 +1847,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 @@ -1851,8 +1859,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"), ]) } @@ -2567,7 +2575,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 @@ -3373,7 +3381,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 @@ -3460,7 +3468,7 @@ final class BuildPlanTests: XCTestCase { ) XCTAssertNoDiagnostics(observability.diagnostics) - var parameters = mockBuildParameters(targetTriple: .wasi) + var parameters = mockBuildParameters(triple: .wasi) parameters.linkingParameters.shouldLinkStaticSwiftStdlib = true let result = try BuildPlanResult(plan: BuildPlan( buildParameters: parameters, @@ -3562,7 +3570,7 @@ final class BuildPlanTests: XCTestCase { try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( canRenameEntrypointFunctionName: true, - targetTriple: triple + triple: triple ), graph: graph, fileSystem: fs, @@ -3759,7 +3767,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 @@ -3836,7 +3844,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 @@ -3846,7 +3854,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 @@ -3909,7 +3917,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 @@ -4063,7 +4071,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 @@ -4126,7 +4134,7 @@ final class BuildPlanTests: XCTestCase { do { let result = try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( - targetTriple: .x86_64Linux, + triple: .x86_64Linux, omitFramePointers: true ), graph: graph, @@ -4182,7 +4190,7 @@ final class BuildPlanTests: XCTestCase { do { let result = try BuildPlanResult(plan: BuildPlan( buildParameters: mockBuildParameters( - targetTriple: .x86_64Linux, + triple: .x86_64Linux, omitFramePointers: false ), graph: graph, @@ -4543,7 +4551,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, @@ -4828,8 +4836,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 @@ -4845,7 +4854,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, ] ) @@ -4855,7 +4864,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, ] ) @@ -4865,12 +4874,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 @@ -4928,8 +4937,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 @@ -4946,7 +4956,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, ] ) @@ -4957,7 +4967,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, ] ) @@ -4969,7 +4979,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, ] ) @@ -4978,7 +4988,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, ] ) @@ -5038,8 +5048,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 @@ -5060,7 +5071,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, ] ) @@ -5071,7 +5082,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, ] ) @@ -5083,7 +5094,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, ] ) @@ -5092,7 +5103,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, ] ) @@ -5142,7 +5153,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 @@ -5446,7 +5457,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 @@ -5579,7 +5590,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 @@ -5704,7 +5715,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 @@ -5833,7 +5844,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 @@ -6106,7 +6117,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"])) @@ -6263,7 +6280,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/CrossCompilationBuildTests.swift b/Tests/BuildTests/CrossCompilationBuildTests.swift new file mode 100644 index 00000000000..f8a9ad600c0 --- /dev/null +++ b/Tests/BuildTests/CrossCompilationBuildTests.swift @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import class Basics.ObservabilitySystem +import struct Basics.Triple +import class Build.BuildPlan +import class Build.ProductBuildDescription +import class Build.SwiftTargetBuildDescription +import func SPMTestSupport.macrosPackageGraph +import func SPMTestSupport.mockBuildParameters +import struct SPMTestSupport.BuildPlanResult +import func SPMTestSupport.XCTAssertMatch +import class TSCBasic.InMemoryFileSystem + +import XCTest + +extension BuildPlanResult { + func allTargets(named name: String) throws -> [SwiftTargetBuildDescription] { + try self.targetMap + .filter { $0.0.targetName == name } + .map { try $1.swiftTarget() } + } + + func allProducts(named name: String) -> [ProductBuildDescription] { + self.productMap + .filter { $0.0.productName == name } + .map { $1 } + } + + func check(triple: Triple, for target: String, file: StaticString = #file, line: UInt = #line) throws { + let target = try self.target(for: target).swiftTarget() + XCTAssertMatch(try target.emitCommandLine(), [.contains(triple.tripleString)], file: file, line: line) + } +} + +final class CrossCompilationBuildPlanTests: XCTestCase { + func testMacros() throws { + let (graph, fs, scope) = try macrosPackageGraph() + + let productsTriple = Triple.arm64Linux + let toolsTriple = Triple.x86_64MacOS + let plan = try BuildPlan( + destinationBuildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true, triple: productsTriple), + 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").contains { $0.target.buildTriple == .tools }) + try result.check(triple: toolsTriple, for: "MMIOMacros") + try result.check(triple: productsTriple, for: "MMIO") + try result.check(triple: productsTriple, for: "Core") + try result.check(triple: productsTriple, for: "HAL") + + let macroProducts = result.allProducts(named: "MMIOMacros") + XCTAssertEqual(macroProducts.count, 1) + let macroProduct = try XCTUnwrap(macroProducts.first) + XCTAssertEqual(macroProduct.buildParameters.triple, toolsTriple) + + // FIXME: check for *toolsTriple* + let mmioTarget = try XCTUnwrap(plan.targets.first { try $0.swiftTarget().target.name == "MMIO" }?.swiftTarget()) + let compileArguments = try mmioTarget.emitCommandLine() + XCTAssertMatch( + compileArguments, + [ + "-I", .equal(mmioTarget.moduleOutputPath.parentDirectory.pathString), + .anySequence, + "-Xfrontend", "-load-plugin-executable", + "-Xfrontend", .contains(toolsTriple.tripleString) + ] + ) + } +} diff --git a/Tests/BuildTests/LLBuildManifestBuilderTests.swift b/Tests/BuildTests/LLBuildManifestBuilderTests.swift index d577e577c7a..0450fcd8f39 100644 --- a/Tests/BuildTests/LLBuildManifestBuilderTests.swift +++ b/Tests/BuildTests/LLBuildManifestBuilderTests.swift @@ -50,7 +50,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .release )) var plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -67,8 +67,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", ] @@ -85,7 +85,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .debug )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -95,12 +95,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", ] @@ -108,7 +108,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() ) @@ -121,8 +121,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( @@ -139,7 +139,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .release )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -152,6 +152,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() @@ -164,7 +170,7 @@ final class LLBuildManifestBuilderTests: XCTestCase { configuration: .debug )) plan = try BuildPlan( - productsBuildParameters: buildParameters, + destinationBuildParameters: buildParameters, toolsBuildParameters: buildParameters, graph: graph, fileSystem: fs, @@ -174,12 +180,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 090dedb431a..6101be96fb1 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 5ef99e3fc59..7b2a1a78378 100644 --- a/Tests/BuildTests/PluginsBuildPlanTests.swift +++ b/Tests/BuildTests/PluginsBuildPlanTests.swift @@ -19,7 +19,7 @@ import PackageModel final class PluginsBuildPlanTests: XCTestCase { func testBuildToolsDatabasePath() throws { try fixture(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in - let (stdout, stderr) = try executeSwiftBuild(fixturePath) + let (stdout, _) = try executeSwiftBuild(fixturePath) XCTAssertMatch(stdout, .contains("Build complete!")) XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/plugins/tools/build.db")))) } @@ -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/CommandsTests/PackageToolTests.swift b/Tests/CommandsTests/PackageToolTests.swift index 4d91794c8bd..dbc6b492dad 100644 --- a/Tests/CommandsTests/PackageToolTests.swift +++ b/Tests/CommandsTests/PackageToolTests.swift @@ -1714,9 +1714,15 @@ final class PackageToolTests: 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": { @@ -1732,11 +1738,13 @@ final class PackageToolTests: 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 @@ -1792,8 +1800,9 @@ final class PackageToolTests: 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( @@ -1819,9 +1828,25 @@ final class PackageToolTests: 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/SwiftToolTests.swift b/Tests/CommandsTests/SwiftToolTests.swift index cc5c291de0e..44e8ea2c75a 100644 --- a/Tests/CommandsTests/SwiftToolTests.swift +++ b/Tests/CommandsTests/SwiftToolTests.swift @@ -255,7 +255,7 @@ final class SwiftToolTests: CommandsTestCase { let explicitDwarfOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc", "-debug-info-format", "dwarf"]) let explicitDwarf = try SwiftTool.createSwiftToolForTest(options: explicitDwarfOptions) plan = try BuildPlan( - productsBuildParameters: explicitDwarf.productsBuildParameters, + destinationBuildParameters: explicitDwarf.productsBuildParameters, toolsBuildParameters: explicitDwarf.toolsBuildParameters, graph: graph, fileSystem: fs, @@ -270,7 +270,7 @@ final class SwiftToolTests: CommandsTestCase { let explicitCodeView = try SwiftTool.createSwiftToolForTest(options: explicitCodeViewOptions) plan = try BuildPlan( - productsBuildParameters: explicitCodeView.productsBuildParameters, + destinationBuildParameters: explicitCodeView.productsBuildParameters, toolsBuildParameters: explicitCodeView.productsBuildParameters, graph: graph, fileSystem: fs, @@ -293,7 +293,7 @@ final class SwiftToolTests: CommandsTestCase { let implicitDwarfOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc"]) let implicitDwarf = try SwiftTool.createSwiftToolForTest(options: implicitDwarfOptions) plan = try BuildPlan( - productsBuildParameters: implicitDwarf.productsBuildParameters, + destinationBuildParameters: implicitDwarf.productsBuildParameters, toolsBuildParameters: implicitDwarf.toolsBuildParameters, graph: graph, fileSystem: fs, @@ -306,7 +306,7 @@ final class SwiftToolTests: CommandsTestCase { let explicitNoDebugInfoOptions = try GlobalOptions.parse(["--triple", "x86_64-unknown-windows-msvc", "-debug-info-format", "none"]) let explicitNoDebugInfo = try SwiftTool.createSwiftToolForTest(options: explicitNoDebugInfoOptions) plan = try BuildPlan( - productsBuildParameters: explicitNoDebugInfo.productsBuildParameters, + destinationBuildParameters: explicitNoDebugInfo.productsBuildParameters, toolsBuildParameters: explicitNoDebugInfo.toolsBuildParameters, graph: graph, fileSystem: fs, diff --git a/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift new file mode 100644 index 00000000000..79076d69adc --- /dev/null +++ b/Tests/PackageGraphTests/CrossCompilationPackageGraphTests.swift @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 testMacros() throws { + let graph = try macrosPackageGraph().graph + 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") + result.checkTarget("Core") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "HAL") + } + result.checkTarget("HAL") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "MMIO") + } + result.checkTarget("MMIO") { result in + result.check(buildTriple: .destination) + result.check(dependencies: "MMIOMacros") + } + result.checkTarget("MMIOMacros") { result in + 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) + } + } + } +} diff --git a/Tests/PackageGraphTests/PackageGraphTests.swift b/Tests/PackageGraphTests/PackageGraphTests.swift index 27af5fee6c4..ab86f67d6a8 100644 --- a/Tests/PackageGraphTests/PackageGraphTests.swift +++ b/Tests/PackageGraphTests/PackageGraphTests.swift @@ -19,8 +19,7 @@ import XCTest import struct TSCBasic.ByteString import class TSCBasic.InMemoryFileSystem -class PackageGraphTests: XCTestCase { - +final class PackageGraphTests: XCTestCase { func testBasic() throws { let fs = InMemoryFileSystem(emptyFiles: "/Foo/Sources/Foo/source.swift", diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift index d06d5bb133d..3d5da4c1255 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/SPMBuildCoreTests/PluginInvocationTests.swift @@ -74,7 +74,8 @@ 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") } @@ -188,13 +189,13 @@ 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: [], @@ -202,6 +203,7 @@ 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) diff --git a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift index 18cbcd13d14..7541f543566 100644 --- a/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift +++ b/Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift @@ -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: ["/fake/path/to/swiftc", "-module-name", "exe", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/exe.build/exe.swiftmodule"]) - try description.checkArguments(for: "lib", graph: graph, partialArguments: ["/fake/path/to/swiftc", "-module-name", "lib", "-emit-dependencies", "-emit-module", "-emit-module-path", "/path/to/build/debug/Modules/lib.swiftmodule"]) + try description.checkArguments( + for: "exe", + graph: graph, + partialArguments: [ + "/fake/path/to/swiftc", + "-module-name", "exe", + "-emit-dependencies", + "-emit-module", + "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/exe.build/exe.swiftmodule" + ] + ) + try description.checkArguments( + for: "lib", + graph: graph, + partialArguments: [ + "/fake/path/to/swiftc", + "-module-name", "lib", + "-emit-dependencies", + "-emit-module", + "-emit-module-path", "/path/to/build/\(buildParameters.triple)/debug/Modules/lib.swiftmodule" + ] + ) } }