From 183ff1ac32577f70e947c3ec5d0738858bdef5e8 Mon Sep 17 00:00:00 2001 From: Boris Buegling Date: Wed, 14 May 2025 12:06:27 -0700 Subject: [PATCH] Add target=name conditional for build settings Add a conditional based on target name. This can be useful for XCConfigs shared between multiple targets. rdar://151321010 --- Sources/SWBCore/Settings/BuiltinMacros.swift | 3 +- Sources/SWBCore/Settings/Settings.swift | 26 ++++++++---- Tests/SWBCoreTests/SettingsTests.swift | 43 ++++++++++++++++++++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/Sources/SWBCore/Settings/BuiltinMacros.swift b/Sources/SWBCore/Settings/BuiltinMacros.swift index 11f2919a..5f18489a 100644 --- a/Sources/SWBCore/Settings/BuiltinMacros.swift +++ b/Sources/SWBCore/Settings/BuiltinMacros.swift @@ -24,8 +24,9 @@ public final class BuiltinMacros { public static let configurationCondition = BuiltinMacros.declareConditionParameter("config") public static let platformCondition = BuiltinMacros.declareConditionParameter("__platform_filter") public static let sdkBuildVersionCondition = BuiltinMacros.declareConditionParameter("_sdk_build_version") + public static let targetNameCondition = BuiltinMacros.declareConditionParameter("target") - private static let allBuiltinConditionParameters = [archCondition, sdkCondition, variantCondition, configurationCondition, platformCondition, sdkBuildVersionCondition] + private static let allBuiltinConditionParameters = [archCondition, sdkCondition, variantCondition, configurationCondition, platformCondition, sdkBuildVersionCondition, targetNameCondition] // MARK: Built-in Macro Definitions diff --git a/Sources/SWBCore/Settings/Settings.swift b/Sources/SWBCore/Settings/Settings.swift index 52617acd..eb3b72cc 100644 --- a/Sources/SWBCore/Settings/Settings.swift +++ b/Sources/SWBCore/Settings/Settings.swift @@ -1592,7 +1592,7 @@ private class SettingsBuilder { if let sdk = boundProperties.sdk, settingsContext.purpose.bindToSDK { for property in impartedBuildProperties ?? [] { // Imparted build properties are always from packages, so force allow platform filter conditionals. - bindConditionParameters(property.buildSettings, sdk, forceAllowPlatformFilterCondition: true) + bindConditionParameters(bindTargetCondition(property.buildSettings), sdk, forceAllowPlatformFilterCondition: true) } } @@ -2751,6 +2751,14 @@ private class SettingsBuilder { } } + func bindTargetCondition(_ table: MacroValueAssignmentTable) -> MacroValueAssignmentTable { + if let target { + return table.bindConditionParameter(BuiltinMacros.targetNameCondition, [target.name]) + } else { + return table + } + } + /// Add the regular project settings. func addProjectSettings(_ config: BuildConfiguration, _ sdk: SDK? = nil) { guard let project else { @@ -2781,11 +2789,11 @@ private class SettingsBuilder { // Load and push a settings table from the file. let info = buildRequestContext.getCachedMacroConfigFile(path, project: project, context: .baseConfiguration) if let sdk = sdk, settingsContext.purpose.bindToSDK { - bindConditionParameters(info.table, sdk) + bindConditionParameters(bindTargetCondition(info.table), sdk) } else { // No bound SDK, so push the project's build settings unmodified. - push(info.table, .exported) + push(bindTargetCondition(info.table), .exported) } self.diagnostics.append(contentsOf: info.diagnostics) for path in info.dependencyPaths { @@ -2810,11 +2818,11 @@ private class SettingsBuilder { // Add the project's config settings. if let sdk, settingsContext.purpose.bindToSDK { - bindConditionParameters(config.buildSettings, sdk) + bindConditionParameters(bindTargetCondition(config.buildSettings), sdk) } else { // No bound SDK, so push the project's build settings unmodified. - push(config.buildSettings, .exported) + push(bindTargetCondition(config.buildSettings), .exported) } // Save the settings table as part of the construction components. @@ -2996,11 +3004,11 @@ private class SettingsBuilder { // Load and push a settings table from the file. let info = buildRequestContext.getCachedMacroConfigFile(path, project: project, context: .baseConfiguration) if let sdk = sdk, settingsContext.purpose.bindToSDK { - bindConditionParameters(info.table, sdk) + bindConditionParameters(bindTargetCondition(info.table), sdk) } else { // No bound SDK, so push the target xcconfig's build settings unmodified. - push(info.table, .exported) + push(bindTargetCondition(info.table), .exported) } self.targetDiagnostics.append(contentsOf: info.diagnostics) for path in info.dependencyPaths { @@ -3019,11 +3027,11 @@ private class SettingsBuilder { // // FIXME: Cache this table, but we can only do that once we share the namespace. if let sdk, settingsContext.purpose.bindToSDK { - bindConditionParameters(config.buildSettings, sdk) + bindConditionParameters(bindTargetCondition(config.buildSettings), sdk) } else { // No bound SDK, so push the target's build settings unmodified. - push(config.buildSettings, .exported) + push(bindTargetCondition(config.buildSettings), .exported) } addSpecializationOverrides(sdk: sdk, usesAutomaticSDK: usesAutomaticSDK) diff --git a/Tests/SWBCoreTests/SettingsTests.swift b/Tests/SWBCoreTests/SettingsTests.swift index df822c5f..47f6cf6a 100644 --- a/Tests/SWBCoreTests/SettingsTests.swift +++ b/Tests/SWBCoreTests/SettingsTests.swift @@ -4837,6 +4837,49 @@ import SWBMacro #expect(settings.globalScope.evaluate(BuiltinMacros.SUPPORTED_PLATFORMS).contains("macosx")) } + @Test + func targetConditionals() async throws { + let testWorkspace = try await TestWorkspace( + "Workspace", + projects: [TestPackageProject( + "aProject", + groupTree: TestGroup("SomeFiles", children: []), + buildConfigurations: [ + TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "macosx", + // config=Debug is added here to ensure target conditionals still compose with existing conditionals. + "OTHER_CFLAGS[target=Target][config=Debug]": "-best", + "OTHER_LDFLAGS[target=Other]": "-other", + "SUPPORTED_PLATFORMS": "$(AVAILABLE_PLATFORMS)", + "SUPPORTS_MACCATALYST": "YES", + ]) + ], + targets: [ + TestStandardTarget("Target", type: .application), + TestStandardTarget("Other", type: .application), + ]) + ]).load(getCore()) + + let context = try await contextForTestData(testWorkspace) + let buildRequestContext = BuildRequestContext(workspaceContext: context) + let testProject = context.workspace.projects[0] + let parameters = BuildParameters(action: .build, configuration: "Debug", activeRunDestination: .macOS) + + do { + let settings = Settings(workspaceContext: context, buildRequestContext: buildRequestContext, parameters: parameters, project: testProject, target: testProject.targets[0]) + #expect(settings.globalScope.evaluate(BuiltinMacros.OTHER_CFLAGS) == ["-best"]) + #expect(settings.globalScope.evaluate(BuiltinMacros.OTHER_LDFLAGS) == []) + } + + do { + let settings = Settings(workspaceContext: context, buildRequestContext: buildRequestContext, parameters: parameters, project: testProject, target: testProject.targets[1]) + #expect(settings.globalScope.evaluate(BuiltinMacros.OTHER_CFLAGS) == []) + #expect(settings.globalScope.evaluate(BuiltinMacros.OTHER_LDFLAGS) == ["-other"]) + } + } + @Test(.requireSDKs(.macOS, .iOS)) func platformConditionals() async throws { let testWorkspace = try await TestWorkspace(