From d408e5f64941a6cda2c899ceb3ee11c19adec669 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Wed, 6 May 2026 11:56:53 -0400 Subject: [PATCH 01/28] WIP - I made a test and it passed --- .../PackageLoading/ManifestJSONParser.swift | 2 + Sources/PackageModel/Manifest/Manifest.swift | 4 ++ .../PackageDescription.swift | 4 ++ .../PackageDescriptionSerialization.swift | 1 + ...geDescriptionSerializationConversion.swift | 4 +- .../ManifestExtensions.swift | 4 ++ .../DefaultSettingsTests.swift | 70 +++++++++++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 Tests/PackageLoadingTests/DefaultSettingsTests.swift diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index e677ae24e1b..dc120d2181e 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -38,6 +38,7 @@ enum ManifestJSONParser { struct Result { var name: String var defaultLocalization: String? + var defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? = [] var platforms: [PlatformDescription] = [] var targets: [TargetDescription] = [] var pkgConfig: String? @@ -107,6 +108,7 @@ enum ManifestJSONParser { return Result( name: input.package.name, defaultLocalization: input.package.defaultLocalization?.tag, + defaultSwiftSettings: [], // TODO: map this platforms: try input.package.platforms.map { try Self.parsePlatforms($0) } ?? [], targets: try input.package.targets.map { try Self.parseTarget(target: $0, identityResolver: identityResolver) }, pkgConfig: input.package.pkgConfig, diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index de069dc15ef..57dca954c51 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -74,6 +74,8 @@ public final class Manifest: Sendable { /// The declared package dependencies. public let dependencies: [PackageDependency] + public let defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? + /// The targets declared in the manifest. public let targets: [TargetDescription] @@ -116,6 +118,7 @@ public final class Manifest: Sendable { packageKind: PackageReference.Kind, packageLocation: String, defaultLocalization: String?, + defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription], version: TSCUtility.Version?, revision: String?, @@ -152,6 +155,7 @@ public final class Manifest: Sendable { self.targetMap = Dictionary(targets.lazy.map { ($0.name, $0) }, uniquingKeysWith: { $1 }) self.traits = traits self.pruneDependencies = pruneDependencies + self.defaultSwiftSettings = defaultSwiftSettings } /// Returns the targets required for a particular product filter. diff --git a/Sources/Runtimes/PackageDescription/PackageDescription.swift b/Sources/Runtimes/PackageDescription/PackageDescription.swift index 60e2d769583..ac8df8e1df6 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescription.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescription.swift @@ -114,6 +114,8 @@ public final class Package { set { swiftLanguageModes = newValue } } + public var defaultSwiftSettings: [SwiftSetting]? + /// The C language standard to use for all C targets in this package. public var cLanguageStandard: CLanguageStandard? @@ -308,6 +310,7 @@ public final class Package { public init( name: String, defaultLocalization: LanguageTag? = nil, + defaultSwiftSettings: [SwiftSetting]? = nil, platforms: [SupportedPlatform]? = nil, pkgConfig: String? = nil, providers: [SystemPackageProvider]? = nil, @@ -320,6 +323,7 @@ public final class Package { ) { self.name = name self.defaultLocalization = defaultLocalization + self.defaultSwiftSettings = defaultSwiftSettings self.platforms = platforms self.pkgConfig = pkgConfig self.providers = providers diff --git a/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift b/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift index d37021c7b04..339dbaa4236 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift @@ -294,6 +294,7 @@ enum Serialization { let name: String let platforms: [SupportedPlatform]? let defaultLocalization: LanguageTag? + let defaultSwiftSettings: [SwiftSetting]? let pkgConfig: String? let providers: [SystemPackageProvider]? let targets: [Target] diff --git a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift index 5d4a0336362..daedd518264 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift @@ -401,9 +401,11 @@ extension Serialization.Package { self.name = package.name self.platforms = package.platforms?.map { .init($0) } self.defaultLocalization = package.defaultLocalization.map { .init($0) } + // TODO: hmmm + self.defaultSwiftSettings = [] self.pkgConfig = package.pkgConfig self.providers = package.providers?.map { .init($0) } - self.targets = package.targets.map { .init($0) } + self.targets = package.targets.map { Serialization.Target.init($0) } self.products = package.products.map { .init($0) } self.traits = package.traits.map { Serialization.Trait($0) } .sorted { $0.name < $1.name } diff --git a/Sources/_InternalTestSupport/ManifestExtensions.swift b/Sources/_InternalTestSupport/ManifestExtensions.swift index 3891c033a11..0a3afaef95c 100644 --- a/Sources/_InternalTestSupport/ManifestExtensions.swift +++ b/Sources/_InternalTestSupport/ManifestExtensions.swift @@ -21,6 +21,7 @@ extension Manifest { displayName: String, path: AbsolutePath = .root, defaultLocalization: String? = nil, + defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription] = [], version: TSCUtility.Version? = nil, toolsVersion: ToolsVersion = .v4, @@ -42,6 +43,7 @@ extension Manifest { packageIdentity: .plain(displayName.lowercased()), packageLocation: path.pathString, defaultLocalization: defaultLocalization, + defaultSwiftSettings: defaultSwiftSettings, platforms: platforms, version: version, toolsVersion: toolsVersion, @@ -226,6 +228,7 @@ extension Manifest { packageIdentity: PackageIdentity, packageLocation: String? = nil, defaultLocalization: String? = nil, + defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription] = [], version: TSCUtility.Version? = nil, toolsVersion: ToolsVersion, @@ -247,6 +250,7 @@ extension Manifest { packageKind: packageKind, packageLocation: packageLocation ?? path.pathString, defaultLocalization: defaultLocalization, + defaultSwiftSettings: defaultSwiftSettings, platforms: platforms, version: version, revision: .none, diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift new file mode 100644 index 00000000000..6a0e432ef20 --- /dev/null +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2026 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 Basics +import PackageLoading +import PackageModel +import _InternalTestSupport +import Testing + +struct DefaultLoadingTests { + @Test( + .tags( + Tag.Feature.TargetSettings + ) + ) + func defaultSettingsApplied() async throws { + let content = """ + import PackageDescription + let package = Package( + name: "Foo", + defaultSwiftSettings: [ + .swiftLanguageMode(.v5), + ], + products: [], + targets: [ + .target( + name: "Foo", + ), + .target( + name: "Bar", + swiftSettings: [ + .swiftLanguageMode(.v6), + ] + ) + ] + ) + """ + + let observability = ObservabilitySystem.makeForTesting() + let (manifest, validationDiagnostics) = try await PackageDescriptionLoadingTests + .loadAndValidateManifest( + content, + toolsVersion: .v6_2, + packageKind: .fileSystem(.root), + manifestLoader: ManifestLoader( + toolchain: try! UserToolchain.default + ), + observabilityScope: observability.topScope + ) + try expectDiagnostics(validationDiagnostics) { results in + results.checkIsEmpty() + } + try expectDiagnostics(observability.diagnostics) { results in + results.checkIsEmpty() + } + + print(manifest.targets[0].settings) + print(manifest.targets[1].settings) + } +} + From 6f567fab4f1309ba44cc3015c3ad97b402b8bc63 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Thu, 7 May 2026 14:24:12 -0400 Subject: [PATCH 02/28] WIP - concept for actually resolving default settings --- Sources/PackageLoading/PackageBuilder.swift | 27 +++++++- .../TargetBuildSettingDescription.swift | 27 ++++++++ .../PackageBuilderTests.swift | 62 +++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index e1b910486bd..e684632382c 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -1086,6 +1086,31 @@ public final class PackageBuilder { } } + private func resolvedSettings(for target: TargetDescription) -> [TargetBuildSettingDescription.Setting] { + var resolved = target.settings + + let defaultSettings = manifest.defaultSwiftSettings ?? [] + + for defaultSetting in defaultSettings { + var eligible = true + + // Look for an existing target setting that takes precedence. If none are found, + // the default is accepted. + for setting in resolved { + if setting.overridesDefault(defaultSetting) { + eligible = false + break + } + } + + if eligible { + resolved.append(defaultSetting) + } + } + + return resolved + } + /// Creates build setting assignment table for the given target. func buildSettings( for target: TargetDescription?, @@ -1103,7 +1128,7 @@ public final class PackageBuilder { table.add(versionAssignment, for: .SWIFT_VERSION) // Process each setting. - for setting in target.settings { + for setting in resolvedSettings(for: target) { if let traits = setting.condition?.traits, traits.intersection(self.enabledTraits.names).isEmpty { // The setting is currently not enabled so we should skip it continue diff --git a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift index 559a8d2ecec..fe61a6df27f 100644 --- a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift +++ b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift @@ -93,5 +93,32 @@ public enum TargetBuildSettingDescription { self.kind = kind self.condition = condition } + + public func overridesDefault(_ defaultSetting: Setting) -> Bool { + guard tool == defaultSetting.tool else { + return false + } + + switch (kind, defaultSetting.kind) { + case (.defaultIsolation, .defaultIsolation): + return true + case (.interoperabilityMode, .interoperabilityMode): + return true + case (.swiftLanguageMode, .swiftLanguageMode): + return true + case (.treatAllWarnings, .treatAllWarnings): + return true + case (.unsafeFlags, .unsafeFlags): + return true + case (.treatWarning(let value, _), .treatWarning(let defaultValue, _)): + return value == defaultValue + case (.enableWarning(let value), .disableWarning(let defaultValue)): + return value == defaultValue + case (.disableWarning(let value), .enableWarning(let defaultValue)): + return value == defaultValue + default: + return false + } + } } } diff --git a/Tests/PackageLoadingTests/PackageBuilderTests.swift b/Tests/PackageLoadingTests/PackageBuilderTests.swift index 8ac94e6a98b..50aac88fc1c 100644 --- a/Tests/PackageLoadingTests/PackageBuilderTests.swift +++ b/Tests/PackageLoadingTests/PackageBuilderTests.swift @@ -3595,6 +3595,68 @@ struct PackageBuilderTests { } } } + + @Test + func defaultSwiftSettingsApplied() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSwiftSettings: [ + .init(tool: .swift, kind: .defaultIsolation(.MainActor)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A" + ), + try TargetDescription( + name: "B", + settings: [] + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) + } + } + } } final class PackageBuilderTester { From 19d41356b23643c041c51bff27ddf46acd13fced Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:02:15 -0400 Subject: [PATCH 03/28] WIP - fill out public manifest API --- .../PackageDescription.swift | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Sources/Runtimes/PackageDescription/PackageDescription.swift b/Sources/Runtimes/PackageDescription/PackageDescription.swift index ac8df8e1df6..8084dd6ed6f 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescription.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescription.swift @@ -114,8 +114,19 @@ public final class Package { set { swiftLanguageModes = newValue } } + /// The default Swift language settings merged with all per-target settings. + @available(_PackageDescription, introduced: 6.5) public var defaultSwiftSettings: [SwiftSetting]? + @available(_PackageDescription, introduced: 6.5) + public var defaultCSettings: [CSetting]? + + @available(_PackageDescription, introduced: 6.5) + public var defaultCXXSettings: [CXXSetting]? + + @available(_PackageDescription, introduced: 6.5) + public var defaultLinkerSettings: [LinkerSetting]? + /// The C language standard to use for all C targets in this package. public var cLanguageStandard: CLanguageStandard? @@ -310,7 +321,6 @@ public final class Package { public init( name: String, defaultLocalization: LanguageTag? = nil, - defaultSwiftSettings: [SwiftSetting]? = nil, platforms: [SupportedPlatform]? = nil, pkgConfig: String? = nil, providers: [SystemPackageProvider]? = nil, @@ -318,12 +328,15 @@ public final class Package { dependencies: [Dependency] = [], targets: [Target] = [], swiftLanguageModes: [SwiftLanguageMode]? = nil, + defaultSwiftSettings: [SwiftSetting]? = nil, cLanguageStandard: CLanguageStandard? = nil, - cxxLanguageStandard: CXXLanguageStandard? = nil + defaultCSettings: [CSetting]? = nil, + cxxLanguageStandard: CXXLanguageStandard? = nil, + defaultCXXSettings: [CXXSetting]? = nil, + defaultLinkerSettings: [LinkerSetting]? = nil ) { self.name = name self.defaultLocalization = defaultLocalization - self.defaultSwiftSettings = defaultSwiftSettings self.platforms = platforms self.pkgConfig = pkgConfig self.providers = providers @@ -332,8 +345,12 @@ public final class Package { self.targets = targets self.traits = [] self.swiftLanguageModes = swiftLanguageModes + self.defaultSwiftSettings = defaultSwiftSettings self.cLanguageStandard = cLanguageStandard + self.defaultCSettings = defaultCSettings self.cxxLanguageStandard = cxxLanguageStandard + self.defaultCXXSettings = defaultCXXSettings + self.defaultLinkerSettings = defaultLinkerSettings registerExitHandler() } @@ -366,8 +383,12 @@ public final class Package { dependencies: [Dependency] = [], targets: [Target] = [], swiftLanguageModes: [SwiftLanguageMode]? = nil, + defaultSwiftSettings: [SwiftSetting]? = nil, cLanguageStandard: CLanguageStandard? = nil, - cxxLanguageStandard: CXXLanguageStandard? = nil + defaultCSettings: [CSetting]? = nil, + cxxLanguageStandard: CXXLanguageStandard? = nil, + defaultCXXSettings: [CXXSetting]? = nil, + defaultLinkerSettings: [LinkerSetting]? = nil ) { self.name = name self.defaultLocalization = defaultLocalization @@ -379,6 +400,7 @@ public final class Package { self.dependencies = dependencies self.targets = targets self.swiftLanguageModes = swiftLanguageModes + self.defaultSwiftSettings = defaultSwiftSettings self.cLanguageStandard = cLanguageStandard self.cxxLanguageStandard = cxxLanguageStandard registerExitHandler() From bd10172fcb25c4742ce52820d890197e6d24d651 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:02:36 -0400 Subject: [PATCH 04/28] WIP - migrate tests to dedicated file --- .../DefaultSettingsTests.swift | 65 ++++++++++++++++++- .../PackageBuilderTests.swift | 62 ------------------ 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 6a0e432ef20..d92fdacab3d 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -22,7 +22,7 @@ struct DefaultLoadingTests { Tag.Feature.TargetSettings ) ) - func defaultSettingsApplied() async throws { + func defaultSettingsManifestLoading() async throws { let content = """ import PackageDescription let package = Package( @@ -66,5 +66,68 @@ struct DefaultLoadingTests { print(manifest.targets[0].settings) print(manifest.targets[1].settings) } + + @Test + func defaultIsolationResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSwiftSettings: [ + .init(tool: .swift, kind: .defaultIsolation(.MainActor)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A" + ), + try TargetDescription( + name: "B", + settings: [] + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) + } + } + } + } diff --git a/Tests/PackageLoadingTests/PackageBuilderTests.swift b/Tests/PackageLoadingTests/PackageBuilderTests.swift index 50aac88fc1c..8ac94e6a98b 100644 --- a/Tests/PackageLoadingTests/PackageBuilderTests.swift +++ b/Tests/PackageLoadingTests/PackageBuilderTests.swift @@ -3595,68 +3595,6 @@ struct PackageBuilderTests { } } } - - @Test - func defaultSwiftSettingsApplied() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSwiftSettings: [ - .init(tool: .swift, kind: .defaultIsolation(.MainActor)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A" - ), - try TargetDescription( - name: "B", - settings: [] - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) - } - } - } } final class PackageBuilderTester { From a6776b86b7a4909e3560b3c1c5cd324cd84e6af1 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:14:32 -0400 Subject: [PATCH 05/28] WIP - header search path test --- .../DefaultSettingsTests.swift | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index d92fdacab3d..87457171f5e 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -129,5 +129,67 @@ struct DefaultLoadingTests { } } -} + @Test + func headerSearchPathResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSwiftSettings: [ + .init(tool: .c, kind: .headerSearchPath("foo")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .headerSearchPath("bar")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) + } + } + } +} From b99608a4f619d7bc496eb64eab8b681fbe82641d Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:23:36 -0400 Subject: [PATCH 06/28] WIP - store all settings in one array --- Sources/PackageLoading/PackageBuilder.swift | 2 +- Sources/PackageModel/Manifest/Manifest.swift | 6 +++--- .../_InternalTestSupport/ManifestExtensions.swift | 8 ++++---- Tests/PackageLoadingTests/DefaultSettingsTests.swift | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index e684632382c..01ac06f2a84 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -1089,7 +1089,7 @@ public final class PackageBuilder { private func resolvedSettings(for target: TargetDescription) -> [TargetBuildSettingDescription.Setting] { var resolved = target.settings - let defaultSettings = manifest.defaultSwiftSettings ?? [] + let defaultSettings = manifest.defaultSettings ?? [] for defaultSetting in defaultSettings { var eligible = true diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 57dca954c51..0931a23652c 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -74,7 +74,7 @@ public final class Manifest: Sendable { /// The declared package dependencies. public let dependencies: [PackageDependency] - public let defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? + public let defaultSettings: [TargetBuildSettingDescription.Setting]? /// The targets declared in the manifest. public let targets: [TargetDescription] @@ -118,7 +118,7 @@ public final class Manifest: Sendable { packageKind: PackageReference.Kind, packageLocation: String, defaultLocalization: String?, - defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], + defaultSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription], version: TSCUtility.Version?, revision: String?, @@ -140,6 +140,7 @@ public final class Manifest: Sendable { self.packageKind = packageKind self.packageLocation = packageLocation self.defaultLocalization = defaultLocalization + self.defaultSettings = defaultSettings self.platforms = platforms self.version = version self.revision = revision @@ -155,7 +156,6 @@ public final class Manifest: Sendable { self.targetMap = Dictionary(targets.lazy.map { ($0.name, $0) }, uniquingKeysWith: { $1 }) self.traits = traits self.pruneDependencies = pruneDependencies - self.defaultSwiftSettings = defaultSwiftSettings } /// Returns the targets required for a particular product filter. diff --git a/Sources/_InternalTestSupport/ManifestExtensions.swift b/Sources/_InternalTestSupport/ManifestExtensions.swift index 0a3afaef95c..ed91d5cd9de 100644 --- a/Sources/_InternalTestSupport/ManifestExtensions.swift +++ b/Sources/_InternalTestSupport/ManifestExtensions.swift @@ -21,7 +21,7 @@ extension Manifest { displayName: String, path: AbsolutePath = .root, defaultLocalization: String? = nil, - defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], + defaultSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription] = [], version: TSCUtility.Version? = nil, toolsVersion: ToolsVersion = .v4, @@ -43,7 +43,7 @@ extension Manifest { packageIdentity: .plain(displayName.lowercased()), packageLocation: path.pathString, defaultLocalization: defaultLocalization, - defaultSwiftSettings: defaultSwiftSettings, + defaultSettings: defaultSettings, platforms: platforms, version: version, toolsVersion: toolsVersion, @@ -228,7 +228,7 @@ extension Manifest { packageIdentity: PackageIdentity, packageLocation: String? = nil, defaultLocalization: String? = nil, - defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], + defaultSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription] = [], version: TSCUtility.Version? = nil, toolsVersion: ToolsVersion, @@ -250,7 +250,7 @@ extension Manifest { packageKind: packageKind, packageLocation: packageLocation ?? path.pathString, defaultLocalization: defaultLocalization, - defaultSwiftSettings: defaultSwiftSettings, + defaultSettings: defaultSettings, platforms: platforms, version: version, revision: .none, diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 87457171f5e..8bc62823c2d 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -27,9 +27,6 @@ struct DefaultLoadingTests { import PackageDescription let package = Package( name: "Foo", - defaultSwiftSettings: [ - .swiftLanguageMode(.v5), - ], products: [], targets: [ .target( @@ -41,7 +38,10 @@ struct DefaultLoadingTests { .swiftLanguageMode(.v6), ] ) - ] + ], + defaultSwiftSettings: [ + .swiftLanguageMode(.v5), + ], ) """ @@ -77,7 +77,7 @@ struct DefaultLoadingTests { let manifest = Manifest.createRootManifest( displayName: "pkg", - defaultSwiftSettings: [ + defaultSettings: [ .init(tool: .swift, kind: .defaultIsolation(.MainActor)) ], toolsVersion: .v6_2, @@ -139,7 +139,7 @@ struct DefaultLoadingTests { let manifest = Manifest.createRootManifest( displayName: "pkg", - defaultSwiftSettings: [ + defaultSettings: [ .init(tool: .c, kind: .headerSearchPath("foo")) ], toolsVersion: .v6_2, From bfa3781a6aa674b0b9d9cd9f184bd74c7d14de75 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:26:55 -0400 Subject: [PATCH 07/28] WIP - define tests --- .../TargetBuildSettingDescription.swift | 2 + .../DefaultSettingsTests.swift | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift index fe61a6df27f..6e8edd05523 100644 --- a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift +++ b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift @@ -110,6 +110,8 @@ public enum TargetBuildSettingDescription { return true case (.unsafeFlags, .unsafeFlags): return true + case (.define, .define): + return true case (.treatWarning(let value, _), .treatWarning(let defaultValue, _)): return value == defaultValue case (.enableWarning(let value), .disableWarning(let defaultValue)): diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 8bc62823c2d..45aee37b400 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -192,4 +192,67 @@ struct DefaultLoadingTests { } } + @Test + func defineResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .c, kind: .define("A=B")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .define("A=C")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B") == false) + #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=C")) + } + } + } + } From e6c890f88bcf57402bde746d66529b4936b37d9c Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:31:25 -0400 Subject: [PATCH 08/28] WIP - linked lib tests --- .../DefaultSettingsTests.swift | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 45aee37b400..6835188e6e2 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -255,4 +255,66 @@ struct DefaultLoadingTests { } } + @Test + func linkedLibraryResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .linker, kind: .linkedLibrary("mylib")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .linker, kind: .linkedLibrary("yourlib")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("yourlib")) + } + } + } } From e0123163d7f41c93739f8cd1516681c1af95b0bc Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:33:47 -0400 Subject: [PATCH 09/28] WIP - linked framework tests --- .../DefaultSettingsTests.swift | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 6835188e6e2..e07cdb59366 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -317,4 +317,68 @@ struct DefaultLoadingTests { } } } + + @Test + func linkedFrameworkResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .linker, kind: .linkedFramework("myframework")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .linker, kind: .linkedFramework("yourframework")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) + #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("yourframework")) + } + } + } + } From 911e698f9e4c7e4a18ebdcb215c30970af6c4d6d Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:48:13 -0400 Subject: [PATCH 10/28] WIP - interoperability tests --- .../DefaultSettingsTests.swift | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index e07cdb59366..49025fd6b35 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -381,4 +381,65 @@ struct DefaultLoadingTests { } } + @Test + func interoperabilityModeResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .interoperabilityMode(.C)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .swift, kind: .interoperabilityMode(.Cxx)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default") == false) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default") == false) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default")) + } + } + } } From c98df065a58e3c939d69acd396a4abb0fc4d7d18 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:51:33 -0400 Subject: [PATCH 11/28] WIP - enableUpcomingFeature tests --- .../DefaultSettingsTests.swift | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 49025fd6b35..c878d0ad7b9 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -442,4 +442,70 @@ struct DefaultLoadingTests { } } } + + @Test + func enableUpcomingFeatureResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .enableUpcomingFeature("foo")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .swift, kind: .enableUpcomingFeature("bar")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) + } + } + } + } From ac908f2594c92e20331242d4a0bd33457fa6825d Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:52:16 -0400 Subject: [PATCH 12/28] WIP - remove some leftover prints --- Tests/PackageLoadingTests/DefaultSettingsTests.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index c878d0ad7b9..7ef5819c23e 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -165,7 +165,6 @@ struct DefaultLoadingTests { try PackageBuilderTester(manifest, in: fs) { package, _ in try package.checkModule("A") { package in - print(package.target.buildSettings) let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) @@ -228,7 +227,6 @@ struct DefaultLoadingTests { try PackageBuilderTester(manifest, in: fs) { package, _ in try package.checkModule("A") { package in - print(package.target.buildSettings) let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) @@ -291,7 +289,6 @@ struct DefaultLoadingTests { try PackageBuilderTester(manifest, in: fs) { package, _ in try package.checkModule("A") { package in - print(package.target.buildSettings) let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) @@ -354,7 +351,6 @@ struct DefaultLoadingTests { try PackageBuilderTester(manifest, in: fs) { package, _ in try package.checkModule("A") { package in - print(package.target.buildSettings) let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) @@ -417,7 +413,6 @@ struct DefaultLoadingTests { try PackageBuilderTester(manifest, in: fs) { package, _ in try package.checkModule("A") { package in - print(package.target.buildSettings) let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) From 4c1ae70f0098bb1f36381d61d2426c55f8757f52 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:55:14 -0400 Subject: [PATCH 13/28] WIP - enableExperimentalFeature tests --- .../DefaultSettingsTests.swift | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 7ef5819c23e..c1e4adbb13c 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -503,4 +503,68 @@ struct DefaultLoadingTests { } } + @Test + func enableExperimentalFeatureResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .enableExperimentalFeature("foo")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .swift, kind: .enableExperimentalFeature("bar")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) + } + } + } } From 97d259e7456b51c8dc0d6ec2d5a4fa4ab82e20eb Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 14:58:37 -0400 Subject: [PATCH 14/28] WIP - strictMemorySafety tests --- .../DefaultSettingsTests.swift | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index c1e4adbb13c..351540d9709 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -567,4 +567,49 @@ struct DefaultLoadingTests { } } } + + @Test + func strictMemorySafetyResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .strictMemorySafety) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [], + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-strict-memory-safety")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-strict-memory-safety")) + } + } + } } From 2d2670ea8cd403a172ded27ee5a5212e3b3192d1 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:04:05 -0400 Subject: [PATCH 15/28] WIP - unsafeFlags tests --- .../DefaultSettingsTests.swift | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 351540d9709..be2901c4f59 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -612,4 +612,64 @@ struct DefaultLoadingTests { } } } + + @Test + func unsafeFlagsResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .unsafeFlags(["foo"])) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + ), + try TargetDescription( + name: "B", + settings: [], + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .unsafeFlags(["bar"])), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo") == false) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) + } + } + } + } From 39d7138042ef8571e126b3c7e1477d98a78bb303 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:21:43 -0400 Subject: [PATCH 16/28] WIP - parse the rest of the default setting types --- .../PackageLoading/ManifestJSONParser.swift | 6 ++ .../PackageDescriptionSerialization.swift | 3 + ...geDescriptionSerializationConversion.swift | 3 + .../DefaultSettingsTests.swift | 59 ++++++++++--------- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index dc120d2181e..993ac24828a 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -39,6 +39,9 @@ enum ManifestJSONParser { var name: String var defaultLocalization: String? var defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? = [] + var defaultCSettings: [TargetBuildSettingDescription.Setting]? = [] + var defaultCXXSettings: [TargetBuildSettingDescription.Setting]? = [] + var defaultLinkerSettings: [TargetBuildSettingDescription.Setting]? = [] var platforms: [PlatformDescription] = [] var targets: [TargetDescription] = [] var pkgConfig: String? @@ -109,6 +112,9 @@ enum ManifestJSONParser { name: input.package.name, defaultLocalization: input.package.defaultLocalization?.tag, defaultSwiftSettings: [], // TODO: map this + defaultCSettings: [], + defaultCXXSettings: [], + defaultLinkerSettings: [], platforms: try input.package.platforms.map { try Self.parsePlatforms($0) } ?? [], targets: try input.package.targets.map { try Self.parseTarget(target: $0, identityResolver: identityResolver) }, pkgConfig: input.package.pkgConfig, diff --git a/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift b/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift index 339dbaa4236..8a1e6e3e506 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescriptionSerialization.swift @@ -295,6 +295,9 @@ enum Serialization { let platforms: [SupportedPlatform]? let defaultLocalization: LanguageTag? let defaultSwiftSettings: [SwiftSetting]? + let defaultCSettings: [CSetting]? + let defaultCXXSettings: [CXXSetting]? + let defaultLinkerSettings: [LinkerSetting]? let pkgConfig: String? let providers: [SystemPackageProvider]? let targets: [Target] diff --git a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift index daedd518264..38c21894eaa 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift @@ -403,6 +403,9 @@ extension Serialization.Package { self.defaultLocalization = package.defaultLocalization.map { .init($0) } // TODO: hmmm self.defaultSwiftSettings = [] + self.defaultCSettings = [] + self.defaultCXXSettings = [] + self.defaultLinkerSettings = [] self.pkgConfig = package.pkgConfig self.providers = package.providers?.map { .init($0) } self.targets = package.targets.map { Serialization.Target.init($0) } diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index be2901c4f59..e0f49aaa9b8 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -42,29 +42,41 @@ struct DefaultLoadingTests { defaultSwiftSettings: [ .swiftLanguageMode(.v5), ], + defaultCSettings: [ + .headerSearchPath("foo"), + ], + defaultCXXSettings: [ + .headerSearchPath("foo"), + ], + defaultLinkerSettings: [ + .linkedLibrary("mylib"), + ], ) """ let observability = ObservabilitySystem.makeForTesting() - let (manifest, validationDiagnostics) = try await PackageDescriptionLoadingTests - .loadAndValidateManifest( - content, - toolsVersion: .v6_2, - packageKind: .fileSystem(.root), - manifestLoader: ManifestLoader( - toolchain: try! UserToolchain.default - ), - observabilityScope: observability.topScope - ) - try expectDiagnostics(validationDiagnostics) { results in - results.checkIsEmpty() - } - try expectDiagnostics(observability.diagnostics) { results in - results.checkIsEmpty() - } + let (manifest, validationDiagnostics) = try await PackageDescriptionLoadingTests + .loadAndValidateManifest( + content, + toolsVersion: .v6_2, + packageKind: .fileSystem(.root), + manifestLoader: ManifestLoader( + toolchain: try! UserToolchain.default + ), + observabilityScope: observability.topScope + ) + try expectDiagnostics(validationDiagnostics) { results in + results.checkIsEmpty() + } + try expectDiagnostics(observability.diagnostics) { results in + results.checkIsEmpty() + } + + let expected: [TargetBuildSettingDescription.Setting] = [ + .init(tool: .swift, kind: .swiftLanguageMode(.v5)) + ] - print(manifest.targets[0].settings) - print(manifest.targets[1].settings) + #expect(manifest.defaultSettings == expected) } @Test @@ -394,16 +406,13 @@ struct DefaultLoadingTests { targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." ), try TargetDescription( name: "B", - publicHeadersPath: ".", settings: [], ), try TargetDescription( name: "C", - publicHeadersPath: ".", settings: [ .init(tool: .swift, kind: .interoperabilityMode(.Cxx)), ] @@ -455,16 +464,13 @@ struct DefaultLoadingTests { targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." ), try TargetDescription( name: "B", - publicHeadersPath: ".", settings: [], ), try TargetDescription( name: "C", - publicHeadersPath: ".", settings: [ .init(tool: .swift, kind: .enableUpcomingFeature("bar")), ] @@ -520,16 +526,13 @@ struct DefaultLoadingTests { targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." ), try TargetDescription( name: "B", - publicHeadersPath: ".", settings: [], ), try TargetDescription( name: "C", - publicHeadersPath: ".", settings: [ .init(tool: .swift, kind: .enableExperimentalFeature("bar")), ] @@ -584,11 +587,9 @@ struct DefaultLoadingTests { targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." ), try TargetDescription( name: "B", - publicHeadersPath: ".", settings: [], ), ] From fdf205ae4bafa634b01c6130154aa3619052eaa7 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:25:48 -0400 Subject: [PATCH 17/28] WIP - swiftLanguageMode tests --- .../DefaultSettingsTests.swift | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index e0f49aaa9b8..af0b71412e3 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -673,4 +673,61 @@ struct DefaultLoadingTests { } } + @Test + func swiftLanguageModeResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .swiftLanguageMode(.v5)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + ), + try TargetDescription( + name: "B", + settings: [], + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .swiftLanguageMode(.v6)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("5")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("5")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("6")) + } + } + } } From fc2c82806e40028ac1ca3b2de446b00beda250d5 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:38:57 -0400 Subject: [PATCH 18/28] WIP - treatAllWarnings tests --- .../DefaultSettingsTests.swift | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index af0b71412e3..775fdcce63c 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -730,4 +730,63 @@ struct DefaultLoadingTests { } } } + + @Test + func treatAllWarningsResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .treatAllWarnings(.error)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + ), + try TargetDescription( + name: "B", + settings: [], + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .treatAllWarnings(.warning)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors") == false) + } + } + } + } From b300c590751936a49cac79901059cf855c8a93db Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:45:24 -0400 Subject: [PATCH 19/28] WIP - treatWarning tests --- .../DefaultSettingsTests.swift | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 775fdcce63c..7a9a4cc5d6d 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -789,4 +789,83 @@ struct DefaultLoadingTests { } } + @Test + func treatWarningResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + "/Sources/D/d.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .treatWarning("foo", .error)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + ), + try TargetDescription( + name: "B", + settings: [], + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .treatWarning("foo", .warning)) + ] + ), + try TargetDescription( + name: "D", + settings: [ + .init(tool: .swift, kind: .treatWarning("bar", .error)) + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Wwarning")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Wwarning") == false) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) + } + } + } + } From 18dd20589991c1e83ff1d0268881b20ab6700551 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:51:11 -0400 Subject: [PATCH 20/28] WIP - enableWarning tests --- .../DefaultSettingsTests.swift | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 7a9a4cc5d6d..fcac6787e45 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -868,4 +868,82 @@ struct DefaultLoadingTests { } } + @Test + func enableWarningResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + "/Sources/D/d.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .c, kind: .enableWarning("foo")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [] + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .enableWarning("bar")), + ] + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .disableWarning("foo")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wbar")) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo") == false) + } + } + } } From ece5e08cc8a1a9cfaee93a4a1071d27b40c522c3 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:53:30 -0400 Subject: [PATCH 21/28] WIP - disableWarning tests --- .../DefaultSettingsTests.swift | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index fcac6787e45..79872210fb9 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -946,4 +946,85 @@ struct DefaultLoadingTests { } } } + + @Test + func disableWarningResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.c", + "/Sources/B/b.c", + "/Sources/C/c.c", + "/Sources/D/d.c", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .c, kind: .disableWarning("foo")) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A", + publicHeadersPath: "." + ), + try TargetDescription( + name: "B", + publicHeadersPath: ".", + settings: [] + ), + try TargetDescription( + name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .disableWarning("bar")), + ] + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .enableWarning("foo")), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + print(package.target.buildSettings) + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-bar")) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) + #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo") == false) + } + } + } + } From 16d026354c80f9f8383302a195f987a2f10916a5 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 15:54:24 -0400 Subject: [PATCH 22/28] WIP - move defaultIsolation tests to the end --- .../DefaultSettingsTests.swift | 123 +++++++++--------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 79872210fb9..18f8ce5511f 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -79,68 +79,6 @@ struct DefaultLoadingTests { #expect(manifest.defaultSettings == expected) } - @Test - func defaultIsolationResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .defaultIsolation(.MainActor)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A" - ), - try TargetDescription( - name: "B", - settings: [] - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) - } - } - } - @Test func headerSearchPathResolution() throws { let fs = InMemoryFileSystem(emptyFiles: @@ -1027,4 +965,65 @@ struct DefaultLoadingTests { } } + @Test + func defaultIsolationResolution() throws { + let fs = InMemoryFileSystem(emptyFiles: + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + ) + + let manifest = Manifest.createRootManifest( + displayName: "pkg", + defaultSettings: [ + .init(tool: .swift, kind: .defaultIsolation(.MainActor)) + ], + toolsVersion: .v6_2, + targets: [ + try TargetDescription( + name: "A" + ), + try TargetDescription( + name: "B", + settings: [] + ), + try TargetDescription( + name: "C", + settings: [ + .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), + ] + ), + ] + ) + + try PackageBuilderTester(manifest, in: fs) { package, _ in + try package.checkModule("A") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("B") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) + } + + try package.checkModule("C") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) + } + } + } } From 80fa6eaa2a9bfabb563e4525901c05d30ea98e29 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Tue, 12 May 2026 16:26:15 -0400 Subject: [PATCH 23/28] WIP - working on manifest loading --- Sources/PackageLoading/ManifestJSONParser.swift | 8 ++++---- Sources/PackageModel/Manifest/Manifest.swift | 13 +++++++++---- .../PackageDescription/PackageDescription.swift | 3 +++ .../PackageDescriptionSerializationConversion.swift | 11 +++++------ .../_InternalTestSupport/ManifestExtensions.swift | 2 +- .../PackageLoadingTests/DefaultSettingsTests.swift | 7 +++++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index 993ac24828a..7d9b7df8f53 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -111,10 +111,10 @@ enum ManifestJSONParser { return Result( name: input.package.name, defaultLocalization: input.package.defaultLocalization?.tag, - defaultSwiftSettings: [], // TODO: map this - defaultCSettings: [], - defaultCXXSettings: [], - defaultLinkerSettings: [], + defaultSwiftSettings: try input.package.defaultSwiftSettings?.map { try .init($0) }, + defaultCSettings: try input.package.defaultCSettings?.map { try .init($0) }, + defaultCXXSettings: try input.package.defaultCXXSettings?.map { try .init($0) }, + defaultLinkerSettings: try input.package.defaultLinkerSettings?.map { try .init($0) }, platforms: try input.package.platforms.map { try Self.parsePlatforms($0) } ?? [], targets: try input.package.targets.map { try Self.parseTarget(target: $0, identityResolver: identityResolver) }, pkgConfig: input.package.pkgConfig, diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 0931a23652c..69369116895 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -74,7 +74,7 @@ public final class Manifest: Sendable { /// The declared package dependencies. public let dependencies: [PackageDependency] - public let defaultSettings: [TargetBuildSettingDescription.Setting]? + public let defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? /// The targets declared in the manifest. public let targets: [TargetDescription] @@ -118,7 +118,7 @@ public final class Manifest: Sendable { packageKind: PackageReference.Kind, packageLocation: String, defaultLocalization: String?, - defaultSettings: [TargetBuildSettingDescription.Setting] = [], + defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription], version: TSCUtility.Version?, revision: String?, @@ -140,7 +140,7 @@ public final class Manifest: Sendable { self.packageKind = packageKind self.packageLocation = packageLocation self.defaultLocalization = defaultLocalization - self.defaultSettings = defaultSettings + self.defaultSwiftSettings = defaultSwiftSettings self.platforms = platforms self.version = version self.revision = revision @@ -614,6 +614,10 @@ public final class Manifest: Sendable { } return self.targetsWithCommonSourceRoot(type: type).count == 1 } + + public var defaultSettings: [TargetBuildSettingDescription.Setting] { + defaultSwiftSettings ?? [] + } } extension Manifest: Hashable { @@ -637,7 +641,7 @@ extension Manifest: Encodable { case name, path, url, version, targetMap, toolsVersion, pkgConfig, providers, cLanguageStandard, cxxLanguageStandard, swiftLanguageVersions, dependencies, products, targets, traits, platforms, packageKind, revision, - defaultLocalization + defaultLocalization, defaultSwiftSettings } /// Coding user info key for dump-package command. @@ -660,6 +664,7 @@ extension Manifest: Encodable { try container.encode(self.toolsVersion, forKey: .toolsVersion) try container.encode(self.defaultLocalization, forKey: .defaultLocalization) + try container.encode(self.defaultSwiftSettings, forKey: .defaultSwiftSettings) try container.encode(self.pkgConfig, forKey: .pkgConfig) try container.encode(self.providers, forKey: .providers) try container.encode(self.cLanguageStandard, forKey: .cLanguageStandard) diff --git a/Sources/Runtimes/PackageDescription/PackageDescription.swift b/Sources/Runtimes/PackageDescription/PackageDescription.swift index 8084dd6ed6f..d119a844893 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescription.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescription.swift @@ -402,7 +402,10 @@ public final class Package { self.swiftLanguageModes = swiftLanguageModes self.defaultSwiftSettings = defaultSwiftSettings self.cLanguageStandard = cLanguageStandard + self.defaultCSettings = defaultCSettings self.cxxLanguageStandard = cxxLanguageStandard + self.defaultCXXSettings = defaultCXXSettings + self.defaultLinkerSettings = defaultLinkerSettings registerExitHandler() } diff --git a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift index 38c21894eaa..9e29045da23 100644 --- a/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift +++ b/Sources/Runtimes/PackageDescription/PackageDescriptionSerializationConversion.swift @@ -401,14 +401,13 @@ extension Serialization.Package { self.name = package.name self.platforms = package.platforms?.map { .init($0) } self.defaultLocalization = package.defaultLocalization.map { .init($0) } - // TODO: hmmm - self.defaultSwiftSettings = [] - self.defaultCSettings = [] - self.defaultCXXSettings = [] - self.defaultLinkerSettings = [] + self.defaultSwiftSettings = package.defaultSwiftSettings?.map { .init($0) } + self.defaultCSettings = package.defaultCSettings?.map { .init($0) } + self.defaultCXXSettings = package.defaultCXXSettings?.map { .init($0) } + self.defaultLinkerSettings = package.defaultLinkerSettings?.map { .init($0) } self.pkgConfig = package.pkgConfig self.providers = package.providers?.map { .init($0) } - self.targets = package.targets.map { Serialization.Target.init($0) } + self.targets = package.targets.map { .init($0) } self.products = package.products.map { .init($0) } self.traits = package.traits.map { Serialization.Trait($0) } .sorted { $0.name < $1.name } diff --git a/Sources/_InternalTestSupport/ManifestExtensions.swift b/Sources/_InternalTestSupport/ManifestExtensions.swift index ed91d5cd9de..b8fb7472205 100644 --- a/Sources/_InternalTestSupport/ManifestExtensions.swift +++ b/Sources/_InternalTestSupport/ManifestExtensions.swift @@ -250,7 +250,7 @@ extension Manifest { packageKind: packageKind, packageLocation: packageLocation ?? path.pathString, defaultLocalization: defaultLocalization, - defaultSettings: defaultSettings, + defaultSwiftSettings: defaultSettings, platforms: platforms, version: version, revision: .none, diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 18f8ce5511f..e7a185e0676 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -46,7 +46,7 @@ struct DefaultLoadingTests { .headerSearchPath("foo"), ], defaultCXXSettings: [ - .headerSearchPath("foo"), + .headerSearchPath("bar"), ], defaultLinkerSettings: [ .linkedLibrary("mylib"), @@ -73,7 +73,10 @@ struct DefaultLoadingTests { } let expected: [TargetBuildSettingDescription.Setting] = [ - .init(tool: .swift, kind: .swiftLanguageMode(.v5)) + .init(tool: .swift, kind: .swiftLanguageMode(.v5)), + .init(tool: .c, kind: .headerSearchPath("foo")), + .init(tool: .cxx, kind: .headerSearchPath("bar")), + .init(tool: .linker, kind: .linkedLibrary("mylib")), ] #expect(manifest.defaultSettings == expected) From c0631d0acc70ef08314145e5296879a03c998b65 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Wed, 13 May 2026 11:42:05 -0400 Subject: [PATCH 24/28] WIP - fix up correctly parsing all default settings --- Sources/PackageLoading/ManifestLoader.swift | 4 ++++ Sources/PackageModel/Manifest/Manifest.swift | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index c3ee04f840e..dda67d14e54 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -368,6 +368,10 @@ public final class ManifestLoader: ManifestLoaderProtocol { packageKind: packageKind, packageLocation: packageLocation, defaultLocalization: parsedManifest.defaultLocalization, + defaultSwiftSettings: parsedManifest.defaultSwiftSettings ?? [], + defaultCSettings: parsedManifest.defaultCSettings ?? [], + defaultCXXSettings: parsedManifest.defaultCXXSettings ?? [], + defaultLinkerSettings: parsedManifest.defaultLinkerSettings ?? [], platforms: parsedManifest.platforms, version: packageVersion?.version, revision: packageVersion?.revision, diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 69369116895..2f9ddaf7f22 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -75,6 +75,9 @@ public final class Manifest: Sendable { public let dependencies: [PackageDependency] public let defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? + public let defaultCSettings: [TargetBuildSettingDescription.Setting]? + public let defaultCXXSettings: [TargetBuildSettingDescription.Setting]? + public let defaultLinkerSettings: [TargetBuildSettingDescription.Setting]? /// The targets declared in the manifest. public let targets: [TargetDescription] @@ -119,6 +122,9 @@ public final class Manifest: Sendable { packageLocation: String, defaultLocalization: String?, defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], + defaultCSettings: [TargetBuildSettingDescription.Setting] = [], + defaultCXXSettings: [TargetBuildSettingDescription.Setting] = [], + defaultLinkerSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription], version: TSCUtility.Version?, revision: String?, @@ -141,6 +147,9 @@ public final class Manifest: Sendable { self.packageLocation = packageLocation self.defaultLocalization = defaultLocalization self.defaultSwiftSettings = defaultSwiftSettings + self.defaultCSettings = defaultCSettings + self.defaultCXXSettings = defaultCXXSettings + self.defaultLinkerSettings = defaultLinkerSettings self.platforms = platforms self.version = version self.revision = revision @@ -616,7 +625,10 @@ public final class Manifest: Sendable { } public var defaultSettings: [TargetBuildSettingDescription.Setting] { - defaultSwiftSettings ?? [] + (defaultSwiftSettings ?? []) + + (defaultCSettings ?? []) + + (defaultCXXSettings ?? []) + + (defaultLinkerSettings ?? []) } } From 0f6abcc83041cb114d3314dc42fea975dd60f97e Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Wed, 13 May 2026 14:00:56 -0400 Subject: [PATCH 25/28] WIP - experiment with unconditional overrides --- .../PackageLoading/ManifestJSONParser.swift | 8 ++++ Sources/PackageLoading/ManifestLoader.swift | 10 +++-- Sources/PackageLoading/PackageBuilder.swift | 44 +++++++++++++------ Sources/PackageModel/Manifest/Manifest.swift | 26 +++-------- .../Manifest/TargetDescription.swift | 19 ++++++++ Sources/Workspace/Workspace+Registry.swift | 1 + .../ManifestExtensions.swift | 2 +- .../DefaultSettingsTests.swift | 7 ++- 8 files changed, 75 insertions(+), 42 deletions(-) diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index 7d9b7df8f53..1ba814e98ce 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -205,6 +205,13 @@ enum ManifestJSONParser { let pluginUsages = target.pluginUsages?.map { TargetDescription.PluginUsage.init($0) } + let explictSettings = TargetDescription.ExplicitSettings( + swift: target.swiftSettings != nil, + c: target.cSettings != nil, + cxx: target.cxxSettings != nil, + linker: target.linkerSettings != nil + ) + return try TargetDescription( name: target.name, dependencies: dependencies, @@ -220,6 +227,7 @@ enum ManifestJSONParser { providers: providers, pluginCapability: pluginCapability, settings: try Self.parseBuildSettings(target), + explicitSettings: explictSettings, checksum: target.checksum, pluginUsages: pluginUsages ) diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index dda67d14e54..44445cccd95 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -361,6 +361,11 @@ public final class ManifestLoader: ManifestLoaderProtocol { )) } + let defaultSettings = (parsedManifest.defaultSwiftSettings ?? []) + + (parsedManifest.defaultCSettings ?? []) + + (parsedManifest.defaultCXXSettings ?? []) + + (parsedManifest.defaultLinkerSettings ?? []) + let manifest = Manifest( displayName: parsedManifest.name, packageIdentity: packageIdentity, @@ -368,10 +373,7 @@ public final class ManifestLoader: ManifestLoaderProtocol { packageKind: packageKind, packageLocation: packageLocation, defaultLocalization: parsedManifest.defaultLocalization, - defaultSwiftSettings: parsedManifest.defaultSwiftSettings ?? [], - defaultCSettings: parsedManifest.defaultCSettings ?? [], - defaultCXXSettings: parsedManifest.defaultCXXSettings ?? [], - defaultLinkerSettings: parsedManifest.defaultLinkerSettings ?? [], + defaultSettings: defaultSettings, platforms: parsedManifest.platforms, version: packageVersion?.version, revision: packageVersion?.revision, diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 01ac06f2a84..9c0e95801c9 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -1089,25 +1089,41 @@ public final class PackageBuilder { private func resolvedSettings(for target: TargetDescription) -> [TargetBuildSettingDescription.Setting] { var resolved = target.settings - let defaultSettings = manifest.defaultSettings ?? [] + if !target.explicitSettings.swift { + resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .swift }) ?? []) + } - for defaultSetting in defaultSettings { - var eligible = true + if !target.explicitSettings.c { + resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .c }) ?? []) + } - // Look for an existing target setting that takes precedence. If none are found, - // the default is accepted. - for setting in resolved { - if setting.overridesDefault(defaultSetting) { - eligible = false - break - } - } + if !target.explicitSettings.cxx { + resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .cxx }) ?? []) + } - if eligible { - resolved.append(defaultSetting) - } + if !target.explicitSettings.linker { + resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .linker }) ?? []) } +// let defaultSettings = manifest.defaultSettings ?? [] +// +// for defaultSetting in defaultSettings { +// var eligible = true +// +// // Look for an existing target setting that takes precedence. If none are found, +// // the default is accepted. +// for setting in resolved { +// if setting.overridesDefault(defaultSetting) { +// eligible = false +// break +// } +// } +// +// if eligible { +// resolved.append(defaultSetting) +// } +// } +// return resolved } diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 2f9ddaf7f22..88d7f0f0d38 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -74,10 +74,7 @@ public final class Manifest: Sendable { /// The declared package dependencies. public let dependencies: [PackageDependency] - public let defaultSwiftSettings: [TargetBuildSettingDescription.Setting]? - public let defaultCSettings: [TargetBuildSettingDescription.Setting]? - public let defaultCXXSettings: [TargetBuildSettingDescription.Setting]? - public let defaultLinkerSettings: [TargetBuildSettingDescription.Setting]? + public let defaultSettings: [TargetBuildSettingDescription.Setting]? /// The targets declared in the manifest. public let targets: [TargetDescription] @@ -121,10 +118,7 @@ public final class Manifest: Sendable { packageKind: PackageReference.Kind, packageLocation: String, defaultLocalization: String?, - defaultSwiftSettings: [TargetBuildSettingDescription.Setting] = [], - defaultCSettings: [TargetBuildSettingDescription.Setting] = [], - defaultCXXSettings: [TargetBuildSettingDescription.Setting] = [], - defaultLinkerSettings: [TargetBuildSettingDescription.Setting] = [], + defaultSettings: [TargetBuildSettingDescription.Setting] = [], platforms: [PlatformDescription], version: TSCUtility.Version?, revision: String?, @@ -146,10 +140,7 @@ public final class Manifest: Sendable { self.packageKind = packageKind self.packageLocation = packageLocation self.defaultLocalization = defaultLocalization - self.defaultSwiftSettings = defaultSwiftSettings - self.defaultCSettings = defaultCSettings - self.defaultCXXSettings = defaultCXXSettings - self.defaultLinkerSettings = defaultLinkerSettings + self.defaultSettings = defaultSettings self.platforms = platforms self.version = version self.revision = revision @@ -623,13 +614,6 @@ public final class Manifest: Sendable { } return self.targetsWithCommonSourceRoot(type: type).count == 1 } - - public var defaultSettings: [TargetBuildSettingDescription.Setting] { - (defaultSwiftSettings ?? []) + - (defaultCSettings ?? []) + - (defaultCXXSettings ?? []) + - (defaultLinkerSettings ?? []) - } } extension Manifest: Hashable { @@ -653,7 +637,7 @@ extension Manifest: Encodable { case name, path, url, version, targetMap, toolsVersion, pkgConfig, providers, cLanguageStandard, cxxLanguageStandard, swiftLanguageVersions, dependencies, products, targets, traits, platforms, packageKind, revision, - defaultLocalization, defaultSwiftSettings + defaultLocalization, defaultSettings } /// Coding user info key for dump-package command. @@ -676,7 +660,7 @@ extension Manifest: Encodable { try container.encode(self.toolsVersion, forKey: .toolsVersion) try container.encode(self.defaultLocalization, forKey: .defaultLocalization) - try container.encode(self.defaultSwiftSettings, forKey: .defaultSwiftSettings) + try container.encode(self.defaultSettings, forKey: .defaultSettings) try container.encode(self.pkgConfig, forKey: .pkgConfig) try container.encode(self.providers, forKey: .providers) try container.encode(self.cLanguageStandard, forKey: .cLanguageStandard) diff --git a/Sources/PackageModel/Manifest/TargetDescription.swift b/Sources/PackageModel/Manifest/TargetDescription.swift index f75de84fd13..1be8a3025dc 100644 --- a/Sources/PackageModel/Manifest/TargetDescription.swift +++ b/Sources/PackageModel/Manifest/TargetDescription.swift @@ -182,7 +182,24 @@ public struct TargetDescription: Hashable, Encodable, Sendable { /// The target-specific build settings declared in this target. public let settings: [TargetBuildSettingDescription.Setting] + public let explicitSettings: ExplicitSettings + + public struct ExplicitSettings: Hashable, Codable, Sendable { + public var swift: Bool + public var c: Bool + public var cxx: Bool + public var linker: Bool + + public init(swift: Bool, c: Bool, cxx: Bool, linker: Bool) { + self.swift = swift + self.c = c + self.cxx = cxx + self.linker = linker + } + public static let all = Self.init(swift: true, c: true, cxx: true, linker: true) + public static let none = Self.init(swift: false, c: false, cxx: false, linker: false) + } /// The binary target checksum. public let checksum: String? @@ -209,6 +226,7 @@ public struct TargetDescription: Hashable, Encodable, Sendable { providers: [SystemPackageProviderDescription]? = nil, pluginCapability: PluginCapability? = nil, settings: [TargetBuildSettingDescription.Setting] = [], + explicitSettings: ExplicitSettings = .all, checksum: String? = nil, pluginUsages: [PluginUsage]? = nil ) throws { @@ -461,6 +479,7 @@ public struct TargetDescription: Hashable, Encodable, Sendable { self.settings = settings self.checksum = checksum self.pluginUsages = pluginUsages + self.explicitSettings = explicitSettings } } diff --git a/Sources/Workspace/Workspace+Registry.swift b/Sources/Workspace/Workspace+Registry.swift index 8cc7514e3cb..19077950d0b 100644 --- a/Sources/Workspace/Workspace+Registry.swift +++ b/Sources/Workspace/Workspace+Registry.swift @@ -292,6 +292,7 @@ extension Workspace { providers: target.providers, pluginCapability: target.pluginCapability, settings: target.settings, + explicitSettings: target.explicitSettings, checksum: target.checksum, pluginUsages: target.pluginUsages ) diff --git a/Sources/_InternalTestSupport/ManifestExtensions.swift b/Sources/_InternalTestSupport/ManifestExtensions.swift index b8fb7472205..ed91d5cd9de 100644 --- a/Sources/_InternalTestSupport/ManifestExtensions.swift +++ b/Sources/_InternalTestSupport/ManifestExtensions.swift @@ -250,7 +250,7 @@ extension Manifest { packageKind: packageKind, packageLocation: packageLocation ?? path.pathString, defaultLocalization: defaultLocalization, - defaultSwiftSettings: defaultSettings, + defaultSettings: defaultSettings, platforms: platforms, version: version, revision: .none, diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index e7a185e0676..4b0e516d655 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -99,19 +99,22 @@ struct DefaultLoadingTests { targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." + publicHeadersPath: ".", + explicitSettings: .none ), try TargetDescription( name: "B", publicHeadersPath: ".", settings: [], + explicitSettings: .all ), try TargetDescription( name: "C", publicHeadersPath: ".", settings: [ .init(tool: .c, kind: .headerSearchPath("bar")), - ] + ], + explicitSettings: .init(swift: false, c: true, cxx: false, linker: false) ), ] ) From 2899598c4610bfb48a2991dbeb6d186b04b04197 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Thu, 14 May 2026 11:16:30 -0400 Subject: [PATCH 26/28] WIP - implement inheritance --- .../PackageLoading/ManifestJSONParser.swift | 2 + Sources/PackageLoading/PackageBuilder.swift | 54 +- .../TargetBuildSettingDescription.swift | 4 +- .../Manifest/TargetDescription.swift | 37 + .../ManifestSourceGeneration.swift | 4 + .../PackageDescription/BuildSettings.swift | 56 ++ .../DefaultSettingsTests.swift | 843 ++++-------------- 7 files changed, 312 insertions(+), 688 deletions(-) diff --git a/Sources/PackageLoading/ManifestJSONParser.swift b/Sources/PackageLoading/ManifestJSONParser.swift index 1ba814e98ce..36ecd6b71f0 100644 --- a/Sources/PackageLoading/ManifestJSONParser.swift +++ b/Sources/PackageLoading/ManifestJSONParser.swift @@ -811,6 +811,8 @@ extension TargetBuildSettingDescription.Kind { } return .defaultIsolation(isolation) + case "inherited": + return .inherited default: throw InternalError("invalid build setting \(name)") } diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 9c0e95801c9..3c2954d40ce 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -1086,9 +1086,36 @@ public final class PackageBuilder { } } - private func resolvedSettings(for target: TargetDescription) -> [TargetBuildSettingDescription.Setting] { - var resolved = target.settings + private func resolvedSettings(for target: TargetDescription) throws -> [TargetBuildSettingDescription.Setting] { + var resolved: [TargetBuildSettingDescription.Setting] = [] + + // first, validate defaults + for setting in manifest.defaultSettings ?? [] { + if case .unsafeFlags = setting.kind { + throw ModuleError.invalidManifestConfig( + self.identity.description, "default settings cannot contain unsafe flags" + ) + } + } + + // copy over all existing settings, substituting in defaults if inherited is encountered. + for setting in target.settings { + switch setting.kind { + case .inherited: + if setting.condition != nil { + throw ModuleError.invalidManifestConfig( + self.identity.description, "inherited settings cannot use conditions" + ) + } + let defaults = manifest.defaultSettings?.filter({ $0.tool == setting.tool }) ?? [] + resolved.append(contentsOf: defaults) + default: + resolved.append(setting) + } + } + + // Now, apply the defaults if nothing explicit is present. if !target.explicitSettings.swift { resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .swift }) ?? []) } @@ -1105,25 +1132,6 @@ public final class PackageBuilder { resolved.append(contentsOf: manifest.defaultSettings?.filter({ $0.tool == .linker }) ?? []) } -// let defaultSettings = manifest.defaultSettings ?? [] -// -// for defaultSetting in defaultSettings { -// var eligible = true -// -// // Look for an existing target setting that takes precedence. If none are found, -// // the default is accepted. -// for setting in resolved { -// if setting.overridesDefault(defaultSetting) { -// eligible = false -// break -// } -// } -// -// if eligible { -// resolved.append(defaultSetting) -// } -// } -// return resolved } @@ -1144,7 +1152,7 @@ public final class PackageBuilder { table.add(versionAssignment, for: .SWIFT_VERSION) // Process each setting. - for setting in resolvedSettings(for: target) { + for setting in try resolvedSettings(for: target) { if let traits = setting.condition?.traits, traits.intersection(self.enabledTraits.names).isEmpty { // The setting is currently not enabled so we should skip it continue @@ -1382,6 +1390,8 @@ public final class PackageBuilder { } values = ["-default-isolation", isolation.rawValue] + case .inherited: + throw InternalError("inherited cannot be in resolved setttings") } // Create an assignment for this setting. diff --git a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift index 6e8edd05523..c6e1f94d320 100644 --- a/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift +++ b/Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift @@ -60,6 +60,8 @@ public enum TargetBuildSettingDescription { case defaultIsolation(DefaultIsolation) + case inherited + public var isUnsafeFlags: Bool { switch self { case .unsafeFlags(let flags): @@ -67,7 +69,7 @@ public enum TargetBuildSettingDescription { return !flags.isEmpty case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode, .enableUpcomingFeature, .enableExperimentalFeature, .strictMemorySafety, .swiftLanguageMode, - .treatAllWarnings, .treatWarning, .enableWarning, .disableWarning, .defaultIsolation: + .treatAllWarnings, .treatWarning, .enableWarning, .disableWarning, .defaultIsolation, .inherited: return false } } diff --git a/Sources/PackageModel/Manifest/TargetDescription.swift b/Sources/PackageModel/Manifest/TargetDescription.swift index 1be8a3025dc..890d76c7e1e 100644 --- a/Sources/PackageModel/Manifest/TargetDescription.swift +++ b/Sources/PackageModel/Manifest/TargetDescription.swift @@ -463,6 +463,43 @@ public struct TargetDescription: Hashable, Encodable, Sendable { ) } } + // ensure that settings and settings presense detection are consistent + if settings.filter({ $0.tool == .swift}).isEmpty == false && explicitSettings.swift == false { + throw Error.disallowedPropertyInTarget( + targetName: name, + targetType: targetType, + propertyName: "explicitSettings", + value: "swift" + ) + } + + if settings.filter({ $0.tool == .c}).isEmpty == false && explicitSettings.c == false { + throw Error.disallowedPropertyInTarget( + targetName: name, + targetType: targetType, + propertyName: "explicitSettings", + value: "c" + ) + } + + if settings.filter({ $0.tool == .cxx}).isEmpty == false && explicitSettings.cxx == false { + throw Error.disallowedPropertyInTarget( + targetName: name, + targetType: targetType, + propertyName: "explicitSettings", + value: "cxx" + ) + } + + if settings.filter({ $0.tool == .linker}).isEmpty == false && explicitSettings.linker == false { + throw Error.disallowedPropertyInTarget( + targetName: name, + targetType: targetType, + propertyName: "explicitSettings", + value: "linker" + ) + } + self.name = name self.dependencies = dependencies self.path = path diff --git a/Sources/PackageModel/ManifestSourceGeneration.swift b/Sources/PackageModel/ManifestSourceGeneration.swift index 9c9a19a3a2d..2bea59f84df 100644 --- a/Sources/PackageModel/ManifestSourceGeneration.swift +++ b/Sources/PackageModel/ManifestSourceGeneration.swift @@ -727,6 +727,8 @@ fileprivate extension SourceCodeFragment { params.append(SourceCodeFragment(from: condition)) } self.init(enum: setting.kind.name, subnodes: params) + case .inherited: + self.init(enum: setting.kind.name, subnodes: []) } } @@ -1215,6 +1217,8 @@ extension TargetBuildSettingDescription.Kind { return "disableWarning" case .defaultIsolation: return "defaultIsolation" + case .inherited: + return "inherited" } } } diff --git a/Sources/Runtimes/PackageDescription/BuildSettings.swift b/Sources/Runtimes/PackageDescription/BuildSettings.swift index 0f4074dbef5..370fb534a48 100644 --- a/Sources/Runtimes/PackageDescription/BuildSettings.swift +++ b/Sources/Runtimes/PackageDescription/BuildSettings.swift @@ -289,6 +289,20 @@ public struct CSetting: Sendable { return CSetting( name: "disableWarning", value: [name], condition: condition) } + + /// Inherit default settings. + /// + /// - Since: First available in PackageDescription 6.5. + /// + /// This setting is a placeholder that will be substituted with any value set by `defaultCSettings`. + @available(_PackageDescription, introduced: 6.2) + public static func inherited() -> CSetting { + return CSetting( + name: "inherited", + value: ["placeholder"], + condition: nil + ) + } } /// A CXX-language build setting. @@ -445,6 +459,20 @@ public struct CXXSetting: Sendable { return CXXSetting( name: "disableWarning", value: [name], condition: condition) } + + /// Inherit default settings. + /// + /// - Since: First available in PackageDescription 6.5. + /// + /// This setting is a placeholder that will be substituted with any value set by `defaultCXXSettings`. + @available(_PackageDescription, introduced: 6.2) + public static func inherited() -> CXXSetting { + return CXXSetting( + name: "inherited", + value: ["placeholder"], + condition: nil + ) + } } /// A Swift language build setting. @@ -714,6 +742,20 @@ public struct SwiftSetting: Sendable { return SwiftSetting( name: "defaultIsolation", value: [isolationString], condition: condition) } + + /// Inherit default settings. + /// + /// - Since: First available in PackageDescription 6.5. + /// + /// This setting is a placeholder that will be substituted with any value set by `defaultSwiftSettings`. + @available(_PackageDescription, introduced: 6.2) + public static func inherited() -> SwiftSetting { + return SwiftSetting( + name: "inherited", + value: ["placeholder"], + condition: nil + ) + } } /// A linker build setting. @@ -778,4 +820,18 @@ public struct LinkerSetting: Sendable { public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "unsafeFlags", value: flags, condition: condition) } + + /// Inherit default settings. + /// + /// - Since: First available in PackageDescription 6.5. + /// + /// This setting is a placeholder that will be substituted with any value set by `defaultLinkerSettings`. + @available(_PackageDescription, introduced: 6.2) + public static func inherited() -> LinkerSetting { + return LinkerSetting( + name: "inherited", + value: ["placeholder"], + condition: nil + ) + } } diff --git a/Tests/PackageLoadingTests/DefaultSettingsTests.swift b/Tests/PackageLoadingTests/DefaultSettingsTests.swift index 4b0e516d655..764fba3936f 100644 --- a/Tests/PackageLoadingTests/DefaultSettingsTests.swift +++ b/Tests/PackageLoadingTests/DefaultSettingsTests.swift @@ -37,7 +37,22 @@ struct DefaultLoadingTests { swiftSettings: [ .swiftLanguageMode(.v6), ] - ) + ), + .target( + name: "Baz", + cSettings: [ + .inherited() + ], + cxxSettings: [ + .inherited() + ], + swiftSettings: [ + .inherited() + ], + linkerSettings: [ + .inherited() + ], + ), ], defaultSwiftSettings: [ .swiftLanguageMode(.v5), @@ -83,38 +98,44 @@ struct DefaultLoadingTests { } @Test - func headerSearchPathResolution() throws { + func swiftToolResolution() throws { let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.c", - "/Sources/B/b.c", - "/Sources/C/c.c", + "/Sources/A/a.swift", + "/Sources/B/b.swift", + "/Sources/C/c.swift", + "/Sources/D/d.swift", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .c, kind: .headerSearchPath("foo")) + .init(tool: .swift, kind: .defaultIsolation(.MainActor)) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - publicHeadersPath: ".", explicitSettings: .none ), try TargetDescription( name: "B", - publicHeadersPath: ".", settings: [], explicitSettings: .all ), try TargetDescription( name: "C", - publicHeadersPath: ".", settings: [ - .init(tool: .c, kind: .headerSearchPath("bar")), + .init(tool: .swift, kind: .defaultIsolation(.nonisolated)) ], - explicitSettings: .init(swift: false, c: true, cxx: false, linker: false) + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) + ), + try TargetDescription( + name: "D", + settings: [ + .init(tool: .swift, kind: .inherited), + .init(tool: .swift, kind: .defaultIsolation(.nonisolated)) + ], + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) ), ] ) @@ -125,7 +146,8 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) } try package.checkModule("B") { package in @@ -133,7 +155,8 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation") == false) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) } try package.checkModule("C") { package in @@ -141,42 +164,66 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) - #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) + #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) } } } @Test - func defineResolution() throws { + func cToolResolution() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.c", "/Sources/B/b.c", "/Sources/C/c.c", + "/Sources/D/d.c", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .c, kind: .define("A=B")) + .init(tool: .c, kind: .headerSearchPath("foo")) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." + publicHeadersPath: ".", + explicitSettings: .none ), try TargetDescription( name: "B", publicHeadersPath: ".", settings: [], + explicitSettings: .all ), try TargetDescription( name: "C", publicHeadersPath: ".", settings: [ - .init(tool: .c, kind: .define("A=C")), - ] + .init(tool: .c, kind: .headerSearchPath("bar")), + ], + explicitSettings: .init(swift: false, c: true, cxx: false, linker: false) + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", + settings: [ + .init(tool: .c, kind: .inherited), + .init(tool: .c, kind: .headerSearchPath("bar")), + ], + explicitSettings: .init(swift: false, c: true, cxx: false, linker: false) ), ] ) @@ -187,7 +234,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) } try package.checkModule("B") { package in @@ -195,7 +242,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo") == false) } try package.checkModule("C") { package in @@ -203,42 +250,64 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=B") == false) - #expect(macosDebugScope.evaluate(.GCC_PREPROCESSOR_DEFINITIONS).contains("A=C")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo") == false) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) } } } @Test - func linkedLibraryResolution() throws { + func cxxToolResolution() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.c", "/Sources/B/b.c", "/Sources/C/c.c", + "/Sources/D/d.c", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .linker, kind: .linkedLibrary("mylib")) + .init(tool: .cxx, kind: .headerSearchPath("foo")) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." + publicHeadersPath: ".", + explicitSettings: .none ), try TargetDescription( name: "B", publicHeadersPath: ".", settings: [], + explicitSettings: .all ), try TargetDescription( name: "C", publicHeadersPath: ".", settings: [ - .init(tool: .linker, kind: .linkedLibrary("yourlib")), - ] + .init(tool: .cxx, kind: .headerSearchPath("bar")), + ], + explicitSettings: .init(swift: false, c: false, cxx: true, linker: false) + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", + settings: [ + .init(tool: .cxx, kind: .inherited), + .init(tool: .cxx, kind: .headerSearchPath("bar")), + ], + explicitSettings: .init(swift: false, c: false, cxx: true, linker: false) ), ] ) @@ -249,7 +318,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) } try package.checkModule("B") { package in @@ -257,7 +326,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo") == false) } try package.checkModule("C") { package in @@ -265,43 +334,66 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) - #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("yourlib")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo") == false) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) + } + + try package.checkModule("D") { package in + let macosDebugScope = BuildSettings.Scope( + package.target.buildSettings, + environment: BuildEnvironment(platform: .macOS, configuration: .debug) + ) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("foo")) + #expect(macosDebugScope.evaluate(.HEADER_SEARCH_PATHS).contains("bar")) } } } @Test - func linkedFrameworkResolution() throws { + func linkerToolResolution() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.c", "/Sources/B/b.c", "/Sources/C/c.c", + "/Sources/D/d.c", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .linker, kind: .linkedFramework("myframework")) + .init(tool: .linker, kind: .linkedLibrary("mylib")) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - publicHeadersPath: "." + publicHeadersPath: ".", + explicitSettings: .none ), try TargetDescription( name: "B", publicHeadersPath: ".", settings: [], + explicitSettings: .all ), try TargetDescription( name: "C", publicHeadersPath: ".", settings: [ - .init(tool: .linker, kind: .linkedFramework("yourframework")), - ] + .init(tool: .linker, kind: .linkedLibrary("yourlib")), + ], + explicitSettings: .init(swift: false, c: false, cxx: false, linker: true) + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", + settings: [ + .init(tool: .linker, kind: .inherited), + .init(tool: .linker, kind: .linkedLibrary("yourlib")), + ], + explicitSettings: .init(swift: false, c: false, cxx: false, linker: true) ), + ] ) @@ -311,7 +403,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) } try package.checkModule("B") { package in @@ -319,7 +411,7 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib") == false) } try package.checkModule("C") { package in @@ -327,709 +419,130 @@ struct DefaultLoadingTests { package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("myframework")) - #expect(macosDebugScope.evaluate(.LINK_FRAMEWORKS).contains("yourframework")) - } - } - } - - @Test - func interoperabilityModeResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .interoperabilityMode(.C)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .interoperabilityMode(.Cxx)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default") == false) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default") == false) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib") == false) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("yourlib")) } - try package.checkModule("C") { package in + try package.checkModule("D") { package in let macosDebugScope = BuildSettings.Scope( package.target.buildSettings, environment: BuildEnvironment(platform: .macOS, configuration: .debug) ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-cxx-interoperability-mode=default")) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("mylib")) + #expect(macosDebugScope.evaluate(.LINK_LIBRARIES).contains("yourlib")) } } } @Test - func enableUpcomingFeatureResolution() throws { + func defaultUnsafeFlagsAreRejected() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.swift", "/Sources/B/b.swift", "/Sources/C/c.swift", + "/Sources/D/d.swift", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .swift, kind: .enableUpcomingFeature("foo")) + .init(tool: .swift, kind: .unsafeFlags(["anything"])) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", + publicHeadersPath: ".", + explicitSettings: .none ), try TargetDescription( name: "B", + publicHeadersPath: ".", settings: [], + explicitSettings: .all ), try TargetDescription( name: "C", + publicHeadersPath: ".", + settings: [ + .init(tool: .swift, kind: .unsafeFlags(["another"])) + ], + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) + ), + try TargetDescription( + name: "D", + publicHeadersPath: ".", settings: [ - .init(tool: .swift, kind: .enableUpcomingFeature("bar")), - ] + .init(tool: .swift, kind: .inherited), + .init(tool: .swift, kind: .unsafeFlags(["another"])) + ], + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) ), ] ) - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-upcoming-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) - } + try PackageBuilderTester(manifest, in: fs) { package, diagnostics in + diagnostics.check( + diagnostic: "configuration of package '\(package.packageIdentity)' is invalid; default settings cannot contain unsafe flags", + severity: .error + ) } } @Test - func enableExperimentalFeatureResolution() throws { + func emptyDefaultsAreAccepted() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", ) let manifest = Manifest.createRootManifest( displayName: "pkg", defaultSettings: [ - .init(tool: .swift, kind: .enableExperimentalFeature("foo")) ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", settings: [ - .init(tool: .swift, kind: .enableExperimentalFeature("bar")), - ] + .init(tool: .swift, kind: .inherited) + ], + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) ), ] ) - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-enable-experimental-feature")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) + try PackageBuilderTester(manifest, in: fs) { package, diagnostics in + try package.checkModule("A") { module in } } } @Test - func strictMemorySafetyResolution() throws { + func inheritanceWithoutSwiftDefaultsIsRejected() throws { let fs = InMemoryFileSystem(emptyFiles: "/Sources/A/a.swift", - "/Sources/B/b.swift", ) let manifest = Manifest.createRootManifest( displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .strictMemorySafety) - ], toolsVersion: .v6_2, targets: [ try TargetDescription( name: "A", - ), - try TargetDescription( - name: "B", - settings: [], + settings: [ + .init(tool: .swift, kind: .inherited) + ], + explicitSettings: .init(swift: true, c: false, cxx: false, linker: false) ), ] ) - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-strict-memory-safety")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-strict-memory-safety")) - } + try PackageBuilderTester(manifest, in: fs) { package, diagnostics in + diagnostics.check( + diagnostic: "configuration of package '\(package.packageIdentity)' is invalid; inheritance cannot be used without default values", + severity: .error + ) } } - @Test - func unsafeFlagsResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .unsafeFlags(["foo"])) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .unsafeFlags(["bar"])), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo") == false) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) - } - } - } - - @Test - func swiftLanguageModeResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .swiftLanguageMode(.v5)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .swiftLanguageMode(.v6)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("5")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("5")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.SWIFT_VERSION).contains("6")) - } - } - } - - @Test - func treatAllWarningsResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .treatAllWarnings(.error)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .treatAllWarnings(.warning)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-warnings-as-errors") == false) - } - } - } - - @Test - func treatWarningResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - "/Sources/D/d.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .treatWarning("foo", .error)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - ), - try TargetDescription( - name: "B", - settings: [], - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .treatWarning("foo", .warning)) - ] - ), - try TargetDescription( - name: "D", - settings: [ - .init(tool: .swift, kind: .treatWarning("bar", .error)) - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Wwarning")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - } - - try package.checkModule("D") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Werror")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("foo")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-Wwarning") == false) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("bar")) - } - } - } - - @Test - func enableWarningResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.c", - "/Sources/B/b.c", - "/Sources/C/c.c", - "/Sources/D/d.c", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .c, kind: .enableWarning("foo")) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - publicHeadersPath: "." - ), - try TargetDescription( - name: "B", - publicHeadersPath: ".", - settings: [] - ), - try TargetDescription( - name: "C", - publicHeadersPath: ".", - settings: [ - .init(tool: .c, kind: .enableWarning("bar")), - ] - ), - try TargetDescription( - name: "D", - publicHeadersPath: ".", - settings: [ - .init(tool: .c, kind: .disableWarning("foo")), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - print(package.target.buildSettings) - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wbar")) - } - - try package.checkModule("D") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo") == false) - } - } - } - - @Test - func disableWarningResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.c", - "/Sources/B/b.c", - "/Sources/C/c.c", - "/Sources/D/d.c", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .c, kind: .disableWarning("foo")) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A", - publicHeadersPath: "." - ), - try TargetDescription( - name: "B", - publicHeadersPath: ".", - settings: [] - ), - try TargetDescription( - name: "C", - publicHeadersPath: ".", - settings: [ - .init(tool: .c, kind: .disableWarning("bar")), - ] - ), - try TargetDescription( - name: "D", - publicHeadersPath: ".", - settings: [ - .init(tool: .c, kind: .enableWarning("foo")), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - print(package.target.buildSettings) - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo")) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-bar")) - } - - try package.checkModule("D") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wfoo")) - #expect(macosDebugScope.evaluate(.OTHER_CFLAGS).contains("-Wno-foo") == false) - } - } - } - - @Test - func defaultIsolationResolution() throws { - let fs = InMemoryFileSystem(emptyFiles: - "/Sources/A/a.swift", - "/Sources/B/b.swift", - "/Sources/C/c.swift", - ) - - let manifest = Manifest.createRootManifest( - displayName: "pkg", - defaultSettings: [ - .init(tool: .swift, kind: .defaultIsolation(.MainActor)) - ], - toolsVersion: .v6_2, - targets: [ - try TargetDescription( - name: "A" - ), - try TargetDescription( - name: "B", - settings: [] - ), - try TargetDescription( - name: "C", - settings: [ - .init(tool: .swift, kind: .defaultIsolation(.nonisolated)), - ] - ), - ] - ) - - try PackageBuilderTester(manifest, in: fs) { package, _ in - try package.checkModule("A") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("B") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor")) - } - - try package.checkModule("C") { package in - let macosDebugScope = BuildSettings.Scope( - package.target.buildSettings, - environment: BuildEnvironment(platform: .macOS, configuration: .debug) - ) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("-default-isolation")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("nonisolated")) - #expect(macosDebugScope.evaluate(.OTHER_SWIFT_FLAGS).contains("MainActor") == false) - } - } - } } From da2f568cd44098a03ca2c0aaf5b91907ea133da0 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Thu, 14 May 2026 11:21:06 -0400 Subject: [PATCH 27/28] WIP - some missing comments --- Sources/PackageModel/Manifest/Manifest.swift | 1 + Sources/PackageModel/Manifest/TargetDescription.swift | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Sources/PackageModel/Manifest/Manifest.swift b/Sources/PackageModel/Manifest/Manifest.swift index 88d7f0f0d38..de37d269c7c 100644 --- a/Sources/PackageModel/Manifest/Manifest.swift +++ b/Sources/PackageModel/Manifest/Manifest.swift @@ -74,6 +74,7 @@ public final class Manifest: Sendable { /// The declared package dependencies. public let dependencies: [PackageDependency] + /// The defaults to be used when resolving settings for all targets. public let defaultSettings: [TargetBuildSettingDescription.Setting]? /// The targets declared in the manifest. diff --git a/Sources/PackageModel/Manifest/TargetDescription.swift b/Sources/PackageModel/Manifest/TargetDescription.swift index 890d76c7e1e..e16b0a5e850 100644 --- a/Sources/PackageModel/Manifest/TargetDescription.swift +++ b/Sources/PackageModel/Manifest/TargetDescription.swift @@ -182,6 +182,8 @@ public struct TargetDescription: Hashable, Encodable, Sendable { /// The target-specific build settings declared in this target. public let settings: [TargetBuildSettingDescription.Setting] + + /// Models the presence of explicitly-defined settings for each tool type. public let explicitSettings: ExplicitSettings public struct ExplicitSettings: Hashable, Codable, Sendable { From d68e423352c70e492988dce62d6f96f3792baa4c Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Thu, 14 May 2026 14:04:15 -0400 Subject: [PATCH 28/28] WIP - introduce some subexpressions to help with parsing --- Sources/PackageLoading/ManifestLoader.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 44445cccd95..e9d9f4dca90 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -361,10 +361,13 @@ public final class ManifestLoader: ManifestLoaderProtocol { )) } - let defaultSettings = (parsedManifest.defaultSwiftSettings ?? []) + - (parsedManifest.defaultCSettings ?? []) + - (parsedManifest.defaultCXXSettings ?? []) + - (parsedManifest.defaultLinkerSettings ?? []) + let defaultSwiftSettings = parsedManifest.defaultSwiftSettings ?? [] + let defaultCSettings = parsedManifest.defaultCSettings ?? [] + let defaultCXXSettings = parsedManifest.defaultCXXSettings ?? [] + let defaultLinkerSettings = parsedManifest.defaultLinkerSettings ?? [] + + let defaultSettings: [TargetBuildSettingDescription.Setting] = + defaultSwiftSettings + defaultCSettings + defaultCXXSettings + defaultLinkerSettings let manifest = Manifest( displayName: parsedManifest.name,