@@ -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
10031006extension  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} 
0 commit comments