Skip to content

Commit d89692b

Browse files
authored
Mirror what native build system does for enabling clang modules (swiftlang#9188)
- the native builder only enables clang modules on Darwin, so we will need to do the same with swift-build.
1 parent 95e4c4f commit d89692b

File tree

6 files changed

+156
-182
lines changed

6 files changed

+156
-182
lines changed

Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift

Lines changed: 132 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -530,14 +530,93 @@ extension PackageGraph.ResolvedModule {
530530
}
531531

532532
struct AllBuildSettings {
533-
typealias BuildSettingsByPlatform =
534-
[ProjectModel.BuildSettings.Platform?: [BuildSettings.Declaration: [String]]]
533+
typealias SingleValueSettingsByPlatform =
534+
[ProjectModel.BuildSettings.Platform?: [ProjectModel.BuildSettings.SingleValueSetting: String]]
535+
typealias MultipleValueSettingsByPlatform =
536+
[ProjectModel.BuildSettings.Platform?: [ProjectModel.BuildSettings.MultipleValueSetting: [String]]]
535537

536-
/// Target-specific build settings declared in the manifest and that apply to the target itself.
537-
var targetSettings: [BuildConfiguration: BuildSettingsByPlatform] = [:]
538+
/// Target-specific single-value build settings declared in the manifest and that apply to the target itself.
539+
var targetSingleValueSettings: [BuildConfiguration: SingleValueSettingsByPlatform] = [:]
540+
541+
/// Target-specific multiple-value build settings declared in the manifest and that apply to the target itself.
542+
var targetMultipleValueSettings: [BuildConfiguration: MultipleValueSettingsByPlatform] = [:]
538543

539-
/// Target-specific build settings that should be imparted to client targets (packages and projects).
540-
var impartedSettings: BuildSettingsByPlatform = [:]
544+
/// Target-specific single-value build settings that should be imparted to client targets (packages and projects).
545+
var impartedSingleValueSettings: SingleValueSettingsByPlatform = [:]
546+
547+
/// Target-specific multiple-value build settings that should be imparted to client targets (packages and projects).
548+
var impartedMultipleValueSettings: MultipleValueSettingsByPlatform = [:]
549+
550+
// MARK: - Convenience Methods
551+
552+
/// Apply all settings to a ProjectModel.BuildSettings instance
553+
func apply(to buildSettings: inout ProjectModel.BuildSettings, for configuration: BuildConfiguration) {
554+
// Apply single value settings for all platforms
555+
if let singleValuesByPlatform = targetSingleValueSettings[configuration] {
556+
for (platform, singleValues) in singleValuesByPlatform {
557+
for (setting, value) in singleValues {
558+
if let platform = platform {
559+
buildSettings[setting, platform] = value
560+
} else {
561+
buildSettings[setting] = value
562+
}
563+
}
564+
}
565+
}
566+
567+
// Apply multiple value settings for all platforms
568+
if let multipleValuesByPlatform = targetMultipleValueSettings[configuration] {
569+
// First, collect all multiple-value settings that are being used
570+
var usedMultipleValueSettings = Set<ProjectModel.BuildSettings.MultipleValueSetting>()
571+
for (_, multipleValues) in multipleValuesByPlatform {
572+
for (setting, _) in multipleValues {
573+
usedMultipleValueSettings.insert(setting)
574+
}
575+
}
576+
577+
// Now apply the platform-specific values
578+
for (platform, multipleValues) in multipleValuesByPlatform {
579+
for (setting, values) in multipleValues {
580+
if let platform = platform {
581+
// Get existing values (should now be initialized with inherited)
582+
let existingValues = buildSettings[setting, platform] ?? ["$(inherited)"]
583+
buildSettings[setting, platform] = existingValues + values
584+
} else {
585+
// Append to existing values instead of overwriting
586+
let existingValues = buildSettings[setting] ?? ["$(inherited)"]
587+
buildSettings[setting] = existingValues + values
588+
}
589+
}
590+
}
591+
}
592+
}
593+
594+
/// Apply imparted settings to a ProjectModel.BuildSettings instance
595+
func applyImparted(to buildSettings: inout ProjectModel.BuildSettings) {
596+
// Apply imparted single value settings for all platforms
597+
for (platform, singleValues) in impartedSingleValueSettings {
598+
for (setting, value) in singleValues {
599+
if let platform = platform {
600+
buildSettings[setting, platform] = value
601+
} else {
602+
buildSettings[setting] = value
603+
}
604+
}
605+
}
606+
607+
// Apply imparted multiple value settings for all platforms
608+
for (platform, multipleValues) in impartedMultipleValueSettings {
609+
for (setting, values) in multipleValues {
610+
if let platform = platform {
611+
let existingValues = buildSettings[setting, platform] ?? ["$(inherited)"]
612+
buildSettings[setting, platform] = existingValues + values
613+
} else {
614+
let existingValues = buildSettings[setting] ?? ["$(inherited)"]
615+
buildSettings[setting] = existingValues + values
616+
}
617+
}
618+
}
619+
}
541620
}
542621

543622
/// Target-specific build settings declared in the manifest and that apply to the target itself.
@@ -552,20 +631,31 @@ extension PackageGraph.ResolvedModule {
552631
for settingAssignment in settingsAssigments {
553632
// Create a build setting value; in some cases there
554633
// isn't a direct mapping to Swift Build build settings.
555-
let pifDeclaration: BuildSettings.Declaration
556634
let values: [String]
635+
let singleValueSetting: ProjectModel.BuildSettings.SingleValueSetting?
636+
let multipleValueSetting: ProjectModel.BuildSettings.MultipleValueSetting?
637+
557638
switch declaration {
558639
case .LINK_FRAMEWORKS:
559-
pifDeclaration = .OTHER_LDFLAGS
640+
singleValueSetting = nil
641+
multipleValueSetting = .OTHER_LDFLAGS
560642
values = settingAssignment.values.flatMap { ["-framework", $0] }
561643
case .LINK_LIBRARIES:
562-
pifDeclaration = .OTHER_LDFLAGS
644+
singleValueSetting = nil
645+
multipleValueSetting = .OTHER_LDFLAGS
563646
values = settingAssignment.values.map { "-l\($0)" }
564647
case .HEADER_SEARCH_PATHS:
565-
pifDeclaration = .HEADER_SEARCH_PATHS
648+
singleValueSetting = nil
649+
multipleValueSetting = .HEADER_SEARCH_PATHS
566650
values = settingAssignment.values.map { self.sourceDirAbsolutePath.pathString + "/" + $0 }
567651
default:
568-
pifDeclaration = ProjectModel.BuildSettings.Declaration(from: declaration)
652+
if declaration.allowsMultipleValues {
653+
singleValueSetting = nil
654+
multipleValueSetting = ProjectModel.BuildSettings.MultipleValueSetting(from: declaration)
655+
} else {
656+
singleValueSetting = ProjectModel.BuildSettings.SingleValueSetting(from: declaration)
657+
multipleValueSetting = nil
658+
}
569659
values = settingAssignment.values
570660
}
571661

@@ -584,26 +674,19 @@ extension PackageGraph.ResolvedModule {
584674
pifPlatform = nil
585675
}
586676

587-
if pifDeclaration == .OTHER_LDFLAGS {
588-
var settingsByDeclaration: [ProjectModel.BuildSettings.Declaration: [String]]
589-
590-
settingsByDeclaration = allSettings.impartedSettings[pifPlatform] ?? [:]
591-
settingsByDeclaration[pifDeclaration, default: []].append(contentsOf: values)
592-
593-
allSettings.impartedSettings[pifPlatform] = settingsByDeclaration
677+
// Handle imparted settings for OTHER_LDFLAGS (always multiple values)
678+
if let multipleValueSetting = multipleValueSetting, multipleValueSetting == .OTHER_LDFLAGS {
679+
allSettings.impartedMultipleValueSettings[pifPlatform, default: [:]][multipleValueSetting, default: []].append(contentsOf: values)
594680
}
595681

596682
for configuration in configurations {
597-
var settingsByDeclaration: [ProjectModel.BuildSettings.Declaration: [String]]
598-
settingsByDeclaration = allSettings.targetSettings[configuration]?[pifPlatform] ?? [:]
599-
600-
if declaration.allowsMultipleValues {
601-
settingsByDeclaration[pifDeclaration, default: []].append(contentsOf: values)
602-
} else {
603-
settingsByDeclaration[pifDeclaration] = values.only.flatMap { [$0] } ?? []
683+
if let multipleValueSetting = multipleValueSetting {
684+
// Handle multiple value settings
685+
allSettings.targetMultipleValueSettings[configuration, default: [:]][pifPlatform, default: [:]][multipleValueSetting, default: []].append(contentsOf: values)
686+
} else if let singleValueSetting = singleValueSetting, let singleValue = values.only {
687+
// Handle single value settings
688+
allSettings.targetSingleValueSettings[configuration, default: [:]][pifPlatform, default: [:]][singleValueSetting] = singleValue
604689
}
605-
606-
allSettings.targetSettings[configuration, default: [:]][pifPlatform] = settingsByDeclaration
607690
}
608691
}
609692
}
@@ -917,88 +1000,8 @@ extension ProjectModel.BuildSettings {
9171000
/// Note that this restricts the settings that can be set by this function to those that can have platform-specific
9181001
/// values, i.e. those in `ProjectModel.BuildSettings.Declaration`. If a platform is specified,
9191002
/// it must be one of the known platforms in `ProjectModel.BuildSettings.Platform`.
920-
mutating func append(values: [String], to setting: Declaration, platform: Platform? = nil) {
921-
// This dichotomy is quite unfortunate but that's currently the underlying model in ProjectModel.BuildSettings.
922-
if let platform {
923-
switch setting {
924-
case .FRAMEWORK_SEARCH_PATHS,
925-
.GCC_PREPROCESSOR_DEFINITIONS,
926-
.HEADER_SEARCH_PATHS,
927-
.OTHER_CFLAGS,
928-
.OTHER_CPLUSPLUSFLAGS,
929-
.OTHER_LDFLAGS,
930-
.OTHER_SWIFT_FLAGS,
931-
.SWIFT_ACTIVE_COMPILATION_CONDITIONS:
932-
// Appending implies the setting is resilient to having ["$(inherited)"]
933-
self.platformSpecificSettings[platform]![setting]!.append(contentsOf: values)
934-
935-
case .SWIFT_VERSION, .DYLIB_INSTALL_NAME_BASE:
936-
self.platformSpecificSettings[platform]![setting] = values // We are not resilient to $(inherited).
937-
938-
case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SPECIALIZATION_SDK_OPTIONS:
939-
fatalError("Unexpected BuildSettings.Declaration: \(setting)")
940-
// Allow staging in new cases
941-
default:
942-
fatalError("Unhandled enum case in BuildSettings.Declaration. Will generate a warning until we have SE-0487")
943-
}
944-
} else {
945-
switch setting {
946-
case .FRAMEWORK_SEARCH_PATHS,
947-
.GCC_PREPROCESSOR_DEFINITIONS,
948-
.HEADER_SEARCH_PATHS,
949-
.OTHER_CFLAGS,
950-
.OTHER_CPLUSPLUSFLAGS,
951-
.OTHER_LDFLAGS,
952-
.OTHER_SWIFT_FLAGS,
953-
.SWIFT_ACTIVE_COMPILATION_CONDITIONS:
954-
let multipleSetting = MultipleValueSetting(from: setting)!
955-
self[multipleSetting, default: ["$(inherited)"]].append(contentsOf: values)
956-
957-
case .SWIFT_VERSION:
958-
self[.SWIFT_VERSION] = values.only.unwrap(orAssert: "Invalid values for 'SWIFT_VERSION': \(values)")
959-
960-
case .DYLIB_INSTALL_NAME_BASE:
961-
self[.DYLIB_INSTALL_NAME_BASE] = values.only.unwrap(orAssert: "Invalid values for 'DYLIB_INSTALL_NAME_BASE': \(values)")
962-
963-
case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SPECIALIZATION_SDK_OPTIONS:
964-
fatalError("Unexpected BuildSettings.Declaration: \(setting)")
965-
// Allow staging in new cases
966-
default:
967-
fatalError("Unhandled enum case in BuildSettings.Declaration. Will generate a warning until we have SE-0487")
968-
}
969-
}
970-
}
9711003
}
9721004

973-
extension ProjectModel.BuildSettings.MultipleValueSetting {
974-
init?(from declaration: ProjectModel.BuildSettings.Declaration) {
975-
switch declaration {
976-
case .GCC_PREPROCESSOR_DEFINITIONS:
977-
self = .GCC_PREPROCESSOR_DEFINITIONS
978-
case .FRAMEWORK_SEARCH_PATHS:
979-
self = .FRAMEWORK_SEARCH_PATHS
980-
case .HEADER_SEARCH_PATHS:
981-
self = .HEADER_SEARCH_PATHS
982-
case .OTHER_CFLAGS:
983-
self = .OTHER_CFLAGS
984-
case .OTHER_CPLUSPLUSFLAGS:
985-
self = .OTHER_CPLUSPLUSFLAGS
986-
case .OTHER_LDFLAGS:
987-
self = .OTHER_LDFLAGS
988-
case .OTHER_SWIFT_FLAGS:
989-
self = .OTHER_SWIFT_FLAGS
990-
case .SPECIALIZATION_SDK_OPTIONS:
991-
self = .SPECIALIZATION_SDK_OPTIONS
992-
case .SWIFT_ACTIVE_COMPILATION_CONDITIONS:
993-
self = .SWIFT_ACTIVE_COMPILATION_CONDITIONS
994-
case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SWIFT_VERSION, .DYLIB_INSTALL_NAME_BASE:
995-
return nil
996-
// Allow staging in new cases
997-
default:
998-
fatalError("Unhandled enum case in BuildSettings.Declaration. Will generate a warning until we have SE-0487")
999-
}
1000-
}
1001-
}
10021005

10031006
extension ProjectModel.BuildSettings.Platform {
10041007
enum Error: Swift.Error {
@@ -1040,7 +1043,6 @@ extension ProjectModel.BuildSettings {
10401043
self[.PRODUCT_NAME] = productName
10411044
self[.PRODUCT_MODULE_NAME] = productName
10421045
self[.PRODUCT_BUNDLE_IDENTIFIER] = "\(packageIdentity).\(productName)".spm_mangledToBundleIdentifier()
1043-
self[.CLANG_ENABLE_MODULES] = "YES"
10441046
self[.SWIFT_PACKAGE_NAME] = packageName ?? nil
10451047

10461048
if !createDylibForDynamicProducts {
@@ -1067,32 +1069,36 @@ extension ProjectModel.BuildSettings {
10671069
}
10681070
}
10691071

1070-
extension ProjectModel.BuildSettings.Declaration {
1071-
init(from declaration: PackageModel.BuildSettings.Declaration) {
1072-
self = switch declaration {
1073-
// Swift.
1072+
extension ProjectModel.BuildSettings.SingleValueSetting {
1073+
init?(from declaration: PackageModel.BuildSettings.Declaration) {
1074+
switch declaration {
1075+
case .SWIFT_VERSION:
1076+
self = .SWIFT_VERSION
1077+
default:
1078+
return nil
1079+
}
1080+
}
1081+
}
1082+
1083+
extension ProjectModel.BuildSettings.MultipleValueSetting {
1084+
init?(from declaration: PackageModel.BuildSettings.Declaration) {
1085+
switch declaration {
10741086
case .SWIFT_ACTIVE_COMPILATION_CONDITIONS:
1075-
.SWIFT_ACTIVE_COMPILATION_CONDITIONS
1087+
self = .SWIFT_ACTIVE_COMPILATION_CONDITIONS
10761088
case .OTHER_SWIFT_FLAGS:
1077-
.OTHER_SWIFT_FLAGS
1078-
case .SWIFT_VERSION:
1079-
.SWIFT_VERSION
1080-
// C family.
1089+
self = .OTHER_SWIFT_FLAGS
10811090
case .GCC_PREPROCESSOR_DEFINITIONS:
1082-
.GCC_PREPROCESSOR_DEFINITIONS
1091+
self = .GCC_PREPROCESSOR_DEFINITIONS
10831092
case .HEADER_SEARCH_PATHS:
1084-
.HEADER_SEARCH_PATHS
1093+
self = .HEADER_SEARCH_PATHS
10851094
case .OTHER_CFLAGS:
1086-
.OTHER_CFLAGS
1095+
self = .OTHER_CFLAGS
10871096
case .OTHER_CPLUSPLUSFLAGS:
1088-
.OTHER_CPLUSPLUSFLAGS
1089-
// Linker.
1097+
self = .OTHER_CPLUSPLUSFLAGS
10901098
case .OTHER_LDFLAGS:
1091-
.OTHER_LDFLAGS
1092-
case .LINK_LIBRARIES, .LINK_FRAMEWORKS:
1093-
preconditionFailure("Should not be reached")
1099+
self = .OTHER_LDFLAGS
10941100
default:
1095-
preconditionFailure("Unexpected BuildSettings.Declaration: \(declaration.name)")
1101+
return nil
10961102
}
10971103
}
10981104
}

Sources/SwiftBuildSupport/PackagePIFBuilder.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -516,16 +516,16 @@ public final class PackagePIFBuilder {
516516
settings[.MACOSX_DEPLOYMENT_TARGET] = builder.deploymentTargets[.macOS] ?? nil
517517
settings[.IPHONEOS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.iOS] ?? nil
518518
if let deploymentTarget_macCatalyst = builder.deploymentTargets[.macCatalyst] ?? nil {
519-
settings
520-
.platformSpecificSettings[.macCatalyst]![.IPHONEOS_DEPLOYMENT_TARGET] = [deploymentTarget_macCatalyst]
519+
settings[.IPHONEOS_DEPLOYMENT_TARGET, .macCatalyst] = deploymentTarget_macCatalyst
521520
}
522521
settings[.TVOS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.tvOS] ?? nil
523522
settings[.WATCHOS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.watchOS] ?? nil
524523
settings[.DRIVERKIT_DEPLOYMENT_TARGET] = builder.deploymentTargets[.driverKit] ?? nil
525524
settings[.XROS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.visionOS] ?? nil
526525

527-
for machoPlatform in [ProjectModel.BuildSettings.Platform.macOS, .macCatalyst, .iOS, .watchOS, .tvOS, .xrOS, .driverKit] {
528-
settings.platformSpecificSettings[machoPlatform]![.DYLIB_INSTALL_NAME_BASE]! = ["@rpath"]
526+
for machoPlatform: ProjectModel.BuildSettings.Platform in [ProjectModel.BuildSettings.Platform.macOS, .macCatalyst, .iOS, .watchOS, .tvOS, .xrOS, .driverKit] {
527+
settings[.DYLIB_INSTALL_NAME_BASE, machoPlatform] = "@rpath"
528+
settings[.CLANG_ENABLE_MODULES, machoPlatform] = "YES"
529529
}
530530

531531
settings[.USE_HEADERMAP] = "NO"
@@ -569,8 +569,7 @@ public final class PackagePIFBuilder {
569569
log(.warning, "Ignoring options '\(platformOptions.joined(separator: " "))' specified for unknown platform \(platform.name)")
570570
continue
571571
}
572-
settings.platformSpecificSettings[pifPlatform]![.SPECIALIZATION_SDK_OPTIONS]!
573-
.append(contentsOf: platformOptions)
572+
settings[.SPECIALIZATION_SDK_OPTIONS, pifPlatform]?.append(contentsOf: platformOptions)
574573
}
575574

576575
let deviceFamilyIDs: Set<Int> = self.delegate.deviceFamilyIDs()
@@ -596,7 +595,7 @@ public final class PackagePIFBuilder {
596595
} catch {
597596
preconditionFailure("Unhandled arm64e platform: \(error)")
598597
}
599-
settings.platformSpecificSettings[pifPlatform]![.ARCHS, default: []].append(contentsOf: ["arm64e"])
598+
settings[.ARCHS, pifPlatform]?.append(contentsOf: ["arm64e"])
600599
}
601600
}
602601

0 commit comments

Comments
 (0)