Skip to content

Commit 6c17a71

Browse files
committed
Pass IPI Clang module names to the Swift compiler
When a Swift target is compiled, swift-build now computes which Clang modules in its transitive dependency closure should be treated as IPI (project-internal) and passes their names via compiler flags. The SKIP_INSTALL condition covers target-produced modules including auto-generated modulemaps. The SRCROOT condition covers explicit modulemaps committed to a project's source tree regardless of SKIP_INSTALL. rdar://177010683
1 parent f1301bc commit 6c17a71

7 files changed

Lines changed: 761 additions & 16 deletions

File tree

Sources/SWBCore/BuildRequestContext.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,19 @@ public final class BuildRequestContext: Sendable {
6464

6565
/// Get the cached settings for the given parameters and project.
6666
package func getCachedSettings(_ parameters: BuildParameters, project: Project, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil) -> Settings {
67-
getCachedSettings(parameters, project: project, target: nil, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: nil, artifactBundleInfo: nil)
67+
getCachedSettings(parameters, project: project, target: nil, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: nil, artifactBundleInfo: nil, ipiClangModuleNames: nil)
6868
}
6969

7070
/// Get the cached settings for the given parameters and target.
71-
package func getCachedSettings(_ parameters: BuildParameters, target: Target, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil) -> Settings {
72-
getCachedSettings(parameters, project: workspaceContext.workspace.project(for: target), target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo)
71+
package func getCachedSettings(_ parameters: BuildParameters, target: Target, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil, ipiClangModuleNames: [String]? = nil) -> Settings {
72+
getCachedSettings(parameters, project: workspaceContext.workspace.project(for: target), target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, ipiClangModuleNames: ipiClangModuleNames)
7373
}
7474

7575
/// Private method to get the cached settings for the given parameters, project, and target.
7676
///
7777
/// - remark: This is private so that clients don't somehow call this with a project which doesn't match the target. There are public methods covering this one.
78-
private func getCachedSettings(_ parameters: BuildParameters, project: Project, target: Target?, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs?, impartedBuildProperties: [ImpartedBuildProperties]?, artifactBundleInfo: [ArtifactBundleInfo]?) -> Settings {
79-
workspaceContext.workspaceSettingsCache.getCachedSettings(parameters, project: project, target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, buildRequestContext: self, filesSignature: filesSignature(for:))
78+
private func getCachedSettings(_ parameters: BuildParameters, project: Project, target: Target?, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs?, impartedBuildProperties: [ImpartedBuildProperties]?, artifactBundleInfo: [ArtifactBundleInfo]?, ipiClangModuleNames: [String]?) -> Settings {
79+
workspaceContext.workspaceSettingsCache.getCachedSettings(parameters, project: project, target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, ipiClangModuleNames: ipiClangModuleNames, buildRequestContext: self, filesSignature: filesSignature(for:))
8080
}
8181

8282
@_spi(Testing) public func getCachedMacroConfigFile(_ path: Path, project: Project? = nil, context: MacroConfigLoadContext) -> MacroConfigInfo {

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,7 @@ public final class BuiltinMacros {
10951095
public static let SWIFT_DISABLE_PARSE_AS_LIBRARY = BuiltinMacros.declareBooleanMacro("SWIFT_DISABLE_PARSE_AS_LIBRARY")
10961096
public static let SWIFT_LIBRARIES_ONLY = BuiltinMacros.declareBooleanMacro("SWIFT_LIBRARIES_ONLY")
10971097
public static let SWIFT_LIBRARY_LEVEL = BuiltinMacros.declareStringMacro("SWIFT_LIBRARY_LEVEL")
1098+
public static let SWIFT_IPI_CLANG_MODULE_NAMES = BuiltinMacros.declareStringListMacro("SWIFT_IPI_CLANG_MODULE_NAMES")
10981099
public static let SWIFT_LIBRARY_PATH = BuiltinMacros.declarePathMacro("SWIFT_LIBRARY_PATH")
10991100
public static let SWIFT_LTO = BuiltinMacros.declareEnumMacro("SWIFT_LTO") as EnumMacroDeclaration<LTOSetting>
11001101
public static let SWIFT_MODULE_NAME = BuiltinMacros.declareStringMacro("SWIFT_MODULE_NAME")
@@ -2347,6 +2348,7 @@ public final class BuiltinMacros {
23472348
SWIFT_INSTALLAPI_LAZY_TYPECHECK,
23482349
SWIFT_LIBRARIES_ONLY,
23492350
SWIFT_LIBRARY_LEVEL,
2351+
SWIFT_IPI_CLANG_MODULE_NAMES,
23502352
SWIFT_LIBRARY_PATH,
23512353
SWIFT_LTO,
23522354
SWIFT_MODULE_ALIASES,

Sources/SWBCore/Settings/Settings.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -797,12 +797,12 @@ public final class Settings: PlatformBuildContext, Sendable {
797797
/// The information about the project model components from which these settings were constructed.
798798
public let constructionComponents: ConstructionComponents
799799

800-
package convenience init(workspaceContext: WorkspaceContext, buildRequestContext: BuildRequestContext, parameters: BuildParameters, project: Project, target: Target? = nil, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil, includeExports: Bool = true, sdkRegistry: (any SDKRegistryLookup)? = nil) {
801-
self.init(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: parameters, settingsContext: SettingsContext(purpose, project: project, target: target), purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, includeExports: includeExports, sdkRegistry: sdkRegistry)
800+
package convenience init(workspaceContext: WorkspaceContext, buildRequestContext: BuildRequestContext, parameters: BuildParameters, project: Project, target: Target? = nil, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil, ipiClangModuleNames: [String]? = nil, includeExports: Bool = true, sdkRegistry: (any SDKRegistryLookup)? = nil) {
801+
self.init(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: parameters, settingsContext: SettingsContext(purpose, project: project, target: target), purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, ipiClangModuleNames: ipiClangModuleNames, includeExports: includeExports, sdkRegistry: sdkRegistry)
802802
}
803803

804804
/// Construct the settings for a project and optionally a target.
805-
package init(workspaceContext: WorkspaceContext, buildRequestContext: BuildRequestContext, parameters: BuildParameters, settingsContext: SettingsContext, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil, includeExports: Bool = true, sdkRegistry: (any SDKRegistryLookup)? = nil) {
805+
package init(workspaceContext: WorkspaceContext, buildRequestContext: BuildRequestContext, parameters: BuildParameters, settingsContext: SettingsContext, purpose: SettingsPurpose = .build, provisioningTaskInputs: ProvisioningTaskInputs? = nil, impartedBuildProperties: [ImpartedBuildProperties]? = nil, artifactBundleInfo: [ArtifactBundleInfo]? = nil, ipiClangModuleNames: [String]? = nil, includeExports: Bool = true, sdkRegistry: (any SDKRegistryLookup)? = nil) {
806806
if let target = settingsContext.target {
807807
precondition(workspaceContext.workspace.project(for: target) === settingsContext.project)
808808
}
@@ -811,7 +811,7 @@ public final class Settings: PlatformBuildContext, Sendable {
811811
self.settingsContext = settingsContext
812812

813813
// Construct the settings table.
814-
let builder = SettingsBuilder(workspaceContext, buildRequestContext, parameters, settingsContext, provisioningTaskInputs, impartedBuildProperties, artifactBundleInfo, includeExports: includeExports, sdkRegistry)
814+
let builder = SettingsBuilder(workspaceContext, buildRequestContext, parameters, settingsContext, provisioningTaskInputs, impartedBuildProperties, artifactBundleInfo, ipiClangModuleNames, includeExports: includeExports, sdkRegistry)
815815
let (boundProperties, boundDeploymentTarget) = MacroNamespace.withExpressionInterningEnabled{ builder.construct() }
816816

817817
// Extract the constructed data.
@@ -1280,6 +1280,7 @@ private class SettingsBuilder: ProjectMatchLookup {
12801280
let provisioningTaskInputs: ProvisioningTaskInputs?
12811281
let impartedBuildProperties: [ImpartedBuildProperties]?
12821282
let artifactBundleInfo: [ArtifactBundleInfo]?
1283+
let ipiClangModuleNames: [String]?
12831284

12841285
/// Whether this builder was constructed specifically for binding properties (versus for general table construction).
12851286
let forBindingProperties: Bool
@@ -1386,7 +1387,7 @@ private class SettingsBuilder: ProjectMatchLookup {
13861387
)
13871388
}
13881389

1389-
init(_ workspaceContext: WorkspaceContext, _ buildRequestContext: BuildRequestContext, _ parameters: BuildParameters, _ settingsContext: SettingsContext, _ provisioningTaskInputs: ProvisioningTaskInputs? = nil, _ impartedBuildProperties: [ImpartedBuildProperties]? = nil, _ artifactBundleInfo: [ArtifactBundleInfo]? = nil, includeExports: Bool = true, forBindingProperties: Bool = false, _ sdkRegistry: (any SDKRegistryLookup)?) {
1390+
init(_ workspaceContext: WorkspaceContext, _ buildRequestContext: BuildRequestContext, _ parameters: BuildParameters, _ settingsContext: SettingsContext, _ provisioningTaskInputs: ProvisioningTaskInputs? = nil, _ impartedBuildProperties: [ImpartedBuildProperties]? = nil, _ artifactBundleInfo: [ArtifactBundleInfo]? = nil, _ ipiClangModuleNames: [String]? = nil, includeExports: Bool = true, forBindingProperties: Bool = false, _ sdkRegistry: (any SDKRegistryLookup)?) {
13901391
self.workspaceContext = workspaceContext
13911392
self.buildRequestContext = buildRequestContext
13921393
self.sdkRegistry = sdkRegistry ?? workspaceContext.sdkRegistry
@@ -1395,6 +1396,7 @@ private class SettingsBuilder: ProjectMatchLookup {
13951396
self.provisioningTaskInputs = provisioningTaskInputs
13961397
self.impartedBuildProperties = impartedBuildProperties
13971398
self.artifactBundleInfo = artifactBundleInfo
1399+
self.ipiClangModuleNames = ipiClangModuleNames
13981400
// FIXME: We should almost certainly not be creating a namespace here, but instead should use an already bound one.
13991401
self.userNamespace = MacroNamespace(parent: workspaceContext.workspace.userNamespace, debugDescription: "settings")
14001402
self._table = MacroValueAssignmentTable(namespace: userNamespace)
@@ -1677,6 +1679,12 @@ private class SettingsBuilder: ProjectMatchLookup {
16771679
}
16781680
}
16791681

1682+
if let ipiClangModuleNames, !ipiClangModuleNames.isEmpty {
1683+
pushTable(.exported) { table in
1684+
table.push(BuiltinMacros.SWIFT_IPI_CLANG_MODULE_NAMES, literal: ipiClangModuleNames)
1685+
}
1686+
}
1687+
16801688
if scope.evaluate(BuiltinMacros.ENABLE_PROJECT_OVERRIDE_SPECS), let projectOverrideSpec = core.specRegistry.findSpecs(ProjectOverridesSpec.self, domain: "").filter({ spec in
16811689
matchesAnyProjectIdentities(scope: scope, projectIdentities: [spec.projectName])
16821690
}).only {

Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ public struct DiscoveredSwiftCompilerToolSpecInfo: DiscoveredCommandLineToolSpec
612612
case emitLocalizedStrings = "emit-localized-strings"
613613
case libraryLevel = "library-level"
614614
case packageName = "package-name-if-supported"
615+
case ipiClangModule = "ipi-clang-module"
615616
case vfsDirectoryRemap = "vfs-directory-remap"
616617
case indexUnitOutputPath = "index-unit-output-path"
617618
case indexUnitOutputPathWithoutWarning = "no-warn-superfluous-index-unit-path"
@@ -1606,6 +1607,22 @@ public final class SwiftCompilerSpec : CompilerSpec, SpecIdentifierType, SwiftDi
16061607
args += ["-library-level", libraryLevel]
16071608
}
16081609

1610+
let ipiNames = cbc.scope.evaluate(BuiltinMacros.SWIFT_IPI_CLANG_MODULE_NAMES)
1611+
if !ipiNames.isEmpty && cbc.scope.evaluate(BuiltinMacros.SWIFT_ENABLE_IPI_LIBRARY_LEVEL) {
1612+
if LibSwiftDriver.supportsDriverFlag(spelled: "-ipi-clang-module") {
1613+
// Driver knows the option; let it forward to the frontend.
1614+
for name in ipiNames {
1615+
args += ["-ipi-clang-module", name]
1616+
}
1617+
} else if toolSpecInfo.toolFeatures.has(.ipiClangModule) {
1618+
// Older driver that doesn't recognise the option, but the
1619+
// frontend supports it. Pass it through directly.
1620+
for name in ipiNames {
1621+
args += ["-Xfrontend", "-ipi-clang-module", "-Xfrontend", name]
1622+
}
1623+
}
1624+
}
1625+
16091626
if toolSpecInfo.toolFeatures.has(.packageName),
16101627
let packageName = cbc.scope.evaluate(BuiltinMacros.SWIFT_PACKAGE_NAME).nilIfEmpty {
16111628
args += ["-package-name", packageName]

Sources/SWBCore/WorkspaceSettingsCache.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@ final class WorkspaceSettingsCache: Sendable {
5252
// Information about consumed artifact bundles
5353
let artifactBundleInfo: [ArtifactBundleInfo]?
5454

55+
// Per-consumer IPI Clang module names.
56+
let ipiClangModuleNames: [String]?
57+
5558
// Using just this instead of all of `impartedBuildProperties` for equality should be fine, because we should only be seeing the same
5659
// `impartedBuildProperties` each time when looking up cached settings.
5760
private var impartedMacroDeclarations: [[MacroDeclaration]]? {
5861
return impartedBuildProperties?.map { return Array($0.buildSettings.valueAssignments.keys) }
5962
}
6063

6164
static func == (lhs: SettingsCacheKey, rhs: SettingsCacheKey) -> Bool {
62-
return lhs.parameters == rhs.parameters && lhs.projectGUID == rhs.projectGUID && lhs.targetGUID == rhs.targetGUID && lhs.purpose == rhs.purpose && lhs.provisioningTaskInputs == rhs.provisioningTaskInputs && lhs.impartedMacroDeclarations == rhs.impartedMacroDeclarations && lhs.artifactBundleInfo == rhs.artifactBundleInfo
65+
return lhs.parameters == rhs.parameters && lhs.projectGUID == rhs.projectGUID && lhs.targetGUID == rhs.targetGUID && lhs.purpose == rhs.purpose && lhs.provisioningTaskInputs == rhs.provisioningTaskInputs && lhs.impartedMacroDeclarations == rhs.impartedMacroDeclarations && lhs.artifactBundleInfo == rhs.artifactBundleInfo && lhs.ipiClangModuleNames == rhs.ipiClangModuleNames
6366
}
6467

6568
func hash(into hasher: inout Hasher) {
@@ -70,12 +73,13 @@ final class WorkspaceSettingsCache: Sendable {
7073
hasher.combine(purpose)
7174
hasher.combine(impartedMacroDeclarations)
7275
hasher.combine(artifactBundleInfo)
76+
hasher.combine(ipiClangModuleNames)
7377
}
7478
}
7579

7680
/// Get the cached settings for the given parameters, without considering the context of any project/target.
7781
public func getCachedSettings(_ parameters: BuildParameters, buildRequestContext: BuildRequestContext, purpose: SettingsPurpose, filesSignature: ([Path]) -> FilesSignature) -> Settings {
78-
let key = SettingsCacheKey(parameters: parameters, projectGUID: nil, targetGUID: nil, purpose: purpose, provisioningTaskInputs: nil, impartedBuildProperties: nil, artifactBundleInfo: nil)
82+
let key = SettingsCacheKey(parameters: parameters, projectGUID: nil, targetGUID: nil, purpose: purpose, provisioningTaskInputs: nil, impartedBuildProperties: nil, artifactBundleInfo: nil, ipiClangModuleNames: nil)
7983

8084
// Check if there were any changes in used xcconfigs
8185
return settingsCache.getOrInsert(key, isValid: { settings in filesSignature(settings.inputPathsAffectingSettings) == settings.inputPathsAffectingSettingsSignature }) {
@@ -87,12 +91,12 @@ final class WorkspaceSettingsCache: Sendable {
8791
/// Private method to get the cached settings for the given parameters, project, and target.
8892
///
8993
/// - remark: This is internal so that clients don't somehow call this with a project which doesn't match the target, except for `BuildRequestContext` which has a cover method for it. There are public methods covering this one.
90-
internal func getCachedSettings(_ parameters: BuildParameters, project: Project, target: Target?, purpose: SettingsPurpose, provisioningTaskInputs: ProvisioningTaskInputs?, impartedBuildProperties: [ImpartedBuildProperties]?, artifactBundleInfo: [ArtifactBundleInfo]?, buildRequestContext: BuildRequestContext, filesSignature: ([Path]) -> FilesSignature) -> Settings {
91-
let key = SettingsCacheKey(parameters: parameters, projectGUID: project.guid, targetGUID: target?.guid, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo)
94+
internal func getCachedSettings(_ parameters: BuildParameters, project: Project, target: Target?, purpose: SettingsPurpose, provisioningTaskInputs: ProvisioningTaskInputs?, impartedBuildProperties: [ImpartedBuildProperties]?, artifactBundleInfo: [ArtifactBundleInfo]?, ipiClangModuleNames: [String]?, buildRequestContext: BuildRequestContext, filesSignature: ([Path]) -> FilesSignature) -> Settings {
95+
let key = SettingsCacheKey(parameters: parameters, projectGUID: project.guid, targetGUID: target?.guid, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, ipiClangModuleNames: ipiClangModuleNames)
9296

9397
// Check if there were any changes in used xcconfigs
9498
return settingsCache.getOrInsert(key, isValid: { settings in filesSignature(settings.inputPathsAffectingSettings) == settings.inputPathsAffectingSettingsSignature }) {
95-
Settings(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: parameters, project: project, target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo)
99+
Settings(workspaceContext: workspaceContext, buildRequestContext: buildRequestContext, parameters: parameters, project: project, target: target, purpose: purpose, provisioningTaskInputs: provisioningTaskInputs, impartedBuildProperties: impartedBuildProperties, artifactBundleInfo: artifactBundleInfo, ipiClangModuleNames: ipiClangModuleNames)
96100
}
97101
}
98102

0 commit comments

Comments
 (0)