From a889bcf6260e232484a81fc30ac39d5225a0b3b0 Mon Sep 17 00:00:00 2001
From: John Bent <theclimbingguide@gmail.com>
Date: Tue, 23 Dec 2025 13:33:10 -0500
Subject: [PATCH 1/6] Fix indentation in .editorconfig

---
 .editorconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.editorconfig b/.editorconfig
index 0d1fce288..51f8f62b6 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -2,7 +2,7 @@ root = true
 
 [*]
 indent_style = space
-indent_size = 2
+indent_size = 4
 end_of_line = lf
 charset = utf-8
 trim_trailing_whitespace = true

From 132188868d818e07ebddf4163be334aa264f9b7e Mon Sep 17 00:00:00 2001
From: John Bent <theclimbingguide@gmail.com>
Date: Tue, 23 Dec 2025 13:33:40 -0500
Subject: [PATCH 2/6] Add Xcode 16 support to XCBuildConfiguration

---
 .../Configuration/XCBuildConfiguration.swift  | 56 ++++++++++++++++---
 1 file changed, 49 insertions(+), 7 deletions(-)

diff --git a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
index 159dc201c..24f6ab1dd 100644
--- a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
+++ b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
@@ -4,10 +4,10 @@ import Foundation
 public final class XCBuildConfiguration: PBXObject {
     // MARK: - Attributes
 
-    /// Base xcconfig file reference.
+    /// Base xcconfig file reference if the file belongs to a ``PBXGroup``.
     var baseConfigurationReference: PBXObjectReference?
 
-    /// Base xcconfig file reference.
+    /// Base xcconfig file reference if the file belongs to a ``PBXGroup``.
     public var baseConfiguration: PBXFileReference? {
         get {
             baseConfigurationReference?.getObject()
@@ -19,6 +19,24 @@ public final class XCBuildConfiguration: PBXObject {
         }
     }
 
+    /// Reference to a ``PBXFileSystemSynchronizedRootGroup`` containing the base xcconfig file.
+    var baseConfigurationReferenceAnchor: PBXObjectReference?
+
+    /// Base xcconfig file path relative to the `baseConfigurationAnchor`.
+    public var baseConfigurationReferenceRelativePath: String?
+
+    /// ``PBXFileSystemSynchronizedRootGroup`` containing the base xcconfig file.
+    public var baseConfigurationAnchor: PBXFileSystemSynchronizedRootGroup? {
+        get {
+            baseConfigurationReferenceAnchor?.getObject()
+        }
+        set {
+            if let newValue {
+                baseConfigurationReferenceAnchor = newValue.reference
+            }
+        }
+    }
+
     /// A map of build settings.
     public var buildSettings: BuildSettings
 
@@ -31,12 +49,23 @@ public final class XCBuildConfiguration: PBXObject {
     ///
     /// - Parameters:
     ///   - name: build configuration name.
-    ///   - baseConfiguration: base configuration.
+    ///   - baseConfiguration: base configuration reference belonging to a group.
+    ///   - baseConfigurationAnchor: the leaf file system synchronized group that contains the base xcconfig file as a descendant.
+    ///   - baseConfigurationRelativePath: relative path from `baseConfigurationAnchor` to the base xcconfig file.
     ///   - buildSettings: dictionary that contains the build settings for this configuration.
+    ///
+    /// - Important:
+    ///     The `baseConfiguration` parameter should be used if the configuration file belongs to a``PBXGroup``.
+    ///     If the configuration file belongs to a ``PBXFileSystemSynchronizedRootGroup``, use the `baseConfigurationAnchor`
+    ///     and `baseConfigurationRelativePath` parameters to address the file instead.
     public init(name: String,
                 baseConfiguration: PBXFileReference? = nil,
+                baseConfigurationAnchor: PBXFileSystemSynchronizedRootGroup? = nil,
+                baseConfigurationRelativePath: String? = nil,
                 buildSettings: BuildSettings = [:]) {
         baseConfigurationReference = baseConfiguration?.reference
+        baseConfigurationReferenceAnchor = baseConfigurationAnchor?.reference
+        baseConfigurationReferenceRelativePath = baseConfigurationRelativePath
         self.buildSettings = buildSettings
         self.name = name
         super.init()
@@ -46,6 +75,8 @@ public final class XCBuildConfiguration: PBXObject {
 
     fileprivate enum CodingKeys: String, CodingKey {
         case baseConfigurationReference
+        case baseConfigurationReferenceAnchor
+        case baseConfigurationReferenceRelativePath
         case buildSettings
         case name
     }
@@ -54,10 +85,15 @@ public final class XCBuildConfiguration: PBXObject {
         let objects = decoder.context.objects
         let objectReferenceRepository = decoder.context.objectReferenceRepository
         let container = try decoder.container(keyedBy: CodingKeys.self)
-        if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
+        // configuration files may be reference by either a pair of PBXFileSystemSynchronizedRootGroup and relative path (Xcode 16)
+        // or a PBXFileReference if the file belongs to a PBXGroup
+        if let baseConfigurationReferenceAnchor: String = try container.decodeIfPresent(.baseConfigurationReferenceAnchor),
+           let baseConfigurationReferenceRelativePath: String = try container.decodeIfPresent(.baseConfigurationReferenceRelativePath)
+        {
+            self.baseConfigurationReferenceAnchor = objectReferenceRepository.getOrCreate(reference: baseConfigurationReferenceAnchor, objects: objects)
+            self.baseConfigurationReferenceRelativePath = baseConfigurationReferenceRelativePath
+        } else if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
             self.baseConfigurationReference = objectReferenceRepository.getOrCreate(reference: baseConfigurationReference, objects: objects)
-        } else {
-            baseConfigurationReference = nil
         }
         buildSettings = try container.decode(BuildSettings.self, forKey: .buildSettings)
         name = try container.decode(.name)
@@ -104,7 +140,13 @@ extension XCBuildConfiguration: PlistSerializable {
         dictionary["isa"] = .string(CommentedString(XCBuildConfiguration.isa))
         dictionary["name"] = .string(CommentedString(name))
         dictionary["buildSettings"] = buildSettings.plist()
-        if let baseConfigurationReference {
+        if let baseConfigurationReferenceAnchor,
+           let baseConfigurationReferenceRelativePath
+        {
+            let synchronizedGroup: PBXFileSystemSynchronizedRootGroup? = baseConfigurationReferenceAnchor.getObject()
+            dictionary["baseConfigurationReferenceAnchor"] = .string(CommentedString(baseConfigurationReferenceAnchor.value, comment: synchronizedGroup?.name))
+            dictionary["baseConfigurationReferenceRelativePath"] = .string(CommentedString(baseConfigurationReferenceRelativePath))
+        } else if let baseConfigurationReference {
             let fileElement: PBXFileElement? = baseConfigurationReference.getObject()
             dictionary["baseConfigurationReference"] = .string(CommentedString(baseConfigurationReference.value, comment: fileElement?.fileName()))
         }

From fee30a782c885fa1420737fb4125d03561c20598 Mon Sep 17 00:00:00 2001
From: John Bent <theclimbingguide@gmail.com>
Date: Tue, 23 Dec 2025 14:24:54 -0500
Subject: [PATCH 3/6] Add tests, fix issue with comment generation

---
 .../project.pbxproj                           | 341 ++++++++++++++++++
 .../AccentColor.colorset/Contents.json        |  11 +
 .../AppIcon.appiconset/Contents.json          |  35 ++
 .../Assets.xcassets/Contents.json             |   6 +
 .../Configs/DevConfig.xcconfig                |   3 +
 .../Configs/ReleaseConfig.xcconfig            |   3 +
 .../Configs/TargetConfig.xcconfig             |   1 +
 .../ContentView.swift                         |  24 ++
 .../Xcode16BuildConfigurationsApp.swift       |  17 +
 .../Configuration/XCBuildConfiguration.swift  |   2 +-
 .../XCBuildConfigurationTests.swift           |  15 +
 .../Objects/Project/PBXProjEncoderTests.swift |  33 ++
 Tests/XcodeProjTests/Tests/Fixtures.swift     |   5 +
 13 files changed, 495 insertions(+), 1 deletion(-)
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations.xcodeproj/project.pbxproj
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AccentColor.colorset/Contents.json
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AppIcon.appiconset/Contents.json
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/Contents.json
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/DevConfig.xcconfig
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/ReleaseConfig.xcconfig
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/TargetConfig.xcconfig
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
 create mode 100644 Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift

diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations.xcodeproj/project.pbxproj b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..fbb1bc5f0
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations.xcodeproj/project.pbxproj
@@ -0,0 +1,341 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 77;
+	objects = {
+
+/* Begin PBXFileReference section */
+		918309852EFB16F800EE08DF /* Xcode16BuildConfigurations.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Xcode16BuildConfigurations.app; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+		918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */ = {
+			isa = PBXFileSystemSynchronizedRootGroup;
+			path = Xcode16BuildConfigurations;
+			sourceTree = "<group>";
+		};
+/* End PBXFileSystemSynchronizedRootGroup section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		918309822EFB16F800EE08DF /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9183097C2EFB16F800EE08DF = {
+			isa = PBXGroup;
+			children = (
+				918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */,
+				918309862EFB16F800EE08DF /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		918309862EFB16F800EE08DF /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				918309852EFB16F800EE08DF /* Xcode16BuildConfigurations.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		918309842EFB16F800EE08DF /* Xcode16BuildConfigurations */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 918309902EFB16F800EE08DF /* Build configuration list for PBXNativeTarget "Xcode16BuildConfigurations" */;
+			buildPhases = (
+				918309812EFB16F800EE08DF /* Sources */,
+				918309822EFB16F800EE08DF /* Frameworks */,
+				918309832EFB16F800EE08DF /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			fileSystemSynchronizedGroups = (
+				918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */,
+			);
+			name = Xcode16BuildConfigurations;
+			packageProductDependencies = (
+			);
+			productName = Xcode16BuildConfigurations;
+			productReference = 918309852EFB16F800EE08DF /* Xcode16BuildConfigurations.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		9183097D2EFB16F800EE08DF /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = 1;
+				LastSwiftUpdateCheck = 2610;
+				LastUpgradeCheck = 2610;
+				TargetAttributes = {
+					918309842EFB16F800EE08DF = {
+						CreatedOnToolsVersion = 26.1;
+					};
+				};
+			};
+			buildConfigurationList = 918309802EFB16F800EE08DF /* Build configuration list for PBXProject "Xcode16BuildConfigurations" */;
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 9183097C2EFB16F800EE08DF;
+			minimizedProjectReferenceProxies = 1;
+			preferredProjectObjectVersion = 77;
+			productRefGroup = 918309862EFB16F800EE08DF /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				918309842EFB16F800EE08DF /* Xcode16BuildConfigurations */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		918309832EFB16F800EE08DF /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		918309812EFB16F800EE08DF /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		9183098E2EFB16F800EE08DF /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;
+			baseConfigurationReferenceRelativePath = Configs/DevConfig.xcconfig;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 26.1;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		9183098F2EFB16F800EE08DF /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;
+			baseConfigurationReferenceRelativePath = Configs/ReleaseConfig.xcconfig;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 26.1;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		918309912EFB16F800EE08DF /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;
+			baseConfigurationReferenceRelativePath = Configs/TargetConfig.xcconfig;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				ENABLE_PREVIEWS = YES;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.Xcode16BuildConfigurations;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				STRING_CATALOG_GENERATE_SYMBOLS = YES;
+				SWIFT_APPROACHABLE_CONCURRENCY = YES;
+				SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		918309922EFB16F800EE08DF /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;
+			baseConfigurationReferenceRelativePath = Configs/TargetConfig.xcconfig;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				ENABLE_PREVIEWS = YES;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.Xcode16BuildConfigurations;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				STRING_CATALOG_GENERATE_SYMBOLS = YES;
+				SWIFT_APPROACHABLE_CONCURRENCY = YES;
+				SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		918309802EFB16F800EE08DF /* Build configuration list for PBXProject "Xcode16BuildConfigurations" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				9183098E2EFB16F800EE08DF /* Debug */,
+				9183098F2EFB16F800EE08DF /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		918309902EFB16F800EE08DF /* Build configuration list for PBXNativeTarget "Xcode16BuildConfigurations" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				918309912EFB16F800EE08DF /* Debug */,
+				918309922EFB16F800EE08DF /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 9183097D2EFB16F800EE08DF /* Project object */;
+}
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AccentColor.colorset/Contents.json b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 000000000..eb8789700
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+  "colors" : [
+    {
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AppIcon.appiconset/Contents.json b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..230588010
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,35 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "tinted"
+        }
+      ],
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/Contents.json b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/Contents.json
new file mode 100644
index 000000000..73c00596a
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/DevConfig.xcconfig b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/DevConfig.xcconfig
new file mode 100644
index 000000000..0abfe77dc
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/DevConfig.xcconfig
@@ -0,0 +1,3 @@
+API_BASE_URL = api.staging.example.com
+ASSETCATALOG_COMPILER_OPTIMIZATION = speed
+TARGETED_DEVICE_FAMILY = 1
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/ReleaseConfig.xcconfig b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/ReleaseConfig.xcconfig
new file mode 100644
index 000000000..56375b0d1
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/ReleaseConfig.xcconfig
@@ -0,0 +1,3 @@
+API_BASE_URL = api.example.com
+ASSETCATALOG_COMPILER_OPTIMIZATION = space
+TARGETED_DEVICE_FAMILY = 1
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/TargetConfig.xcconfig b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/TargetConfig.xcconfig
new file mode 100644
index 000000000..565be09fe
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Configs/TargetConfig.xcconfig
@@ -0,0 +1 @@
+TARGETED_DEVICE_FAMILY = 1,2
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
new file mode 100644
index 000000000..26b52dfdd
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
@@ -0,0 +1,24 @@
+//
+//  ContentView.swift
+//  Xcode16BuildConfigurations
+//
+//  Created by John Bent on 12/23/25.
+//
+
+import SwiftUI
+
+struct ContentView: View {
+    var body: some View {
+        VStack {
+            Image(systemName: "globe")
+                .imageScale(.large)
+                .foregroundStyle(.tint)
+            Text("Hello, world!")
+        }
+        .padding()
+    }
+}
+
+#Preview {
+    ContentView()
+}
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift
new file mode 100644
index 000000000..43e1a0781
--- /dev/null
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift
@@ -0,0 +1,17 @@
+//
+//  Xcode16BuildConfigurationsApp.swift
+//  Xcode16BuildConfigurations
+//
+//  Created by John Bent on 12/23/25.
+//
+
+import SwiftUI
+
+@main
+struct Xcode16BuildConfigurationsApp: App {
+    var body: some Scene {
+        WindowGroup {
+            ContentView()
+        }
+    }
+}
diff --git a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
index 24f6ab1dd..c019c3ba5 100644
--- a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
+++ b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
@@ -144,7 +144,7 @@ extension XCBuildConfiguration: PlistSerializable {
            let baseConfigurationReferenceRelativePath
         {
             let synchronizedGroup: PBXFileSystemSynchronizedRootGroup? = baseConfigurationReferenceAnchor.getObject()
-            dictionary["baseConfigurationReferenceAnchor"] = .string(CommentedString(baseConfigurationReferenceAnchor.value, comment: synchronizedGroup?.name))
+            dictionary["baseConfigurationReferenceAnchor"] = .string(CommentedString(baseConfigurationReferenceAnchor.value, comment: synchronizedGroup?.path))
             dictionary["baseConfigurationReferenceRelativePath"] = .string(CommentedString(baseConfigurationReferenceRelativePath))
         } else if let baseConfigurationReference {
             let fileElement: PBXFileElement? = baseConfigurationReference.getObject()
diff --git a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
index e29ef2d54..64d357f8a 100644
--- a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
+++ b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
@@ -85,6 +85,21 @@ final class XCBuildConfigurationTests: XCTestCase {
         XCTAssertEqual(subject.buildSettings["OTHER_LDFLAGS"], ["flag1", "flag2", "flag3"])
     }
 
+    func test_configuration_files_in_synchronized_group() {
+        let synchronizedGroup = PBXFileSystemSynchronizedRootGroup.fixture(sourceTree: .group,
+                                                                           path: "Xcode16BuildConfigurations",
+                                                                           explicitFileTypes: [:],
+                                                                           exceptions: [],
+                                                                           explicitFolders: [])
+        let subject = XCBuildConfiguration(name: "Debug",
+                                           baseConfigurationAnchor: synchronizedGroup,
+                                           baseConfigurationRelativePath: "Configs/DevConfig.xcconfig",
+                                           buildSettings: [:])
+        XCTAssertNil(subject.baseConfigurationReference)
+        XCTAssertNotNil(subject.baseConfigurationReferenceAnchor)
+        XCTAssertNotNil(subject.baseConfigurationReferenceRelativePath)
+    }
+
     private func testDictionary() -> [String: Any] {
         [
             "baseConfigurationReference": "baseConfigurationReference",
diff --git a/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift b/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
index af5233ce0..aa7424c5e 100644
--- a/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
+++ b/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
@@ -341,6 +341,35 @@
             line = lines.validate(line: "/* End PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */", after: line)
         }
 
+        // MARK: File system synchronized build configuration files
+
+        func test_fileSystemSynchronizedBuildConfigurationFiles() throws {
+            try loadProjectWithConfigurationFilesInSynchronizedGroup()
+            let settings = PBXOutputSettings(projNavigatorFileOrder: .byFilenameGroupsFirst)
+            let lines = lines(fromFile: encodeProject(settings: settings))
+
+            let beginGroup = lines.findLine("/* Begin XCBuildConfiguration section */")
+            var line = lines.validate(line: "9183098E2EFB16F800EE08DF /* Debug */ = {", after: beginGroup)
+            line = lines.validate(line: "isa = XCBuildConfiguration;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceRelativePath = Configs/DevConfig.xcconfig;", after: line)
+
+            line = lines.validate(line: "9183098F2EFB16F800EE08DF /* Release */ = {", after: line)
+            line = lines.validate(line: "isa = XCBuildConfiguration;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceRelativePath = Configs/ReleaseConfig.xcconfig;", after: line)
+
+            line = lines.validate(line: "918309912EFB16F800EE08DF /* Debug */ = {", after: line)
+            line = lines.validate(line: "isa = XCBuildConfiguration;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceRelativePath = Configs/TargetConfig.xcconfig;", after: line)
+
+            line = lines.validate(line: "918309922EFB16F800EE08DF /* Release */ = {", after: line)
+            line = lines.validate(line: "isa = XCBuildConfiguration;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceAnchor = 918309872EFB16F800EE08DF /* Xcode16BuildConfigurations */;", after: line)
+            line = lines.validate(line: "baseConfigurationReferenceRelativePath = Configs/TargetConfig.xcconfig;", after: line)
+        }
+
         // MARK: - Projects
 
         func test_ProjectReferenceOrder() throws {
@@ -558,6 +587,10 @@
         private func loadProjectWithShellScriptBuildPhase() throws {
             proj = try PBXProj(data: projectWithCustomShellScript())
         }
+
+        private func loadProjectWithConfigurationFilesInSynchronizedGroup() throws {
+            proj = try PBXProj(data: projectWithConfigurationFilesInSynchronizedGroup())
+        }
     }
 
     // MARK: - Line validations
diff --git a/Tests/XcodeProjTests/Tests/Fixtures.swift b/Tests/XcodeProjTests/Tests/Fixtures.swift
index 32a0e24fd..045a7ce49 100644
--- a/Tests/XcodeProjTests/Tests/Fixtures.swift
+++ b/Tests/XcodeProjTests/Tests/Fixtures.swift
@@ -55,3 +55,8 @@ func projectWithCustomShellScript() throws -> Data {
     let iosProjectWithShellScript = fixturesPath() + "Xcode16ProjectReferenceOrder/Test.xcodeproj/project.pbxproj"
     return try Data(contentsOf: iosProjectWithShellScript.url)
 }
+
+func projectWithConfigurationFilesInSynchronizedGroup() throws -> Data {
+    let projectWithConfigurationFilesInSynchronizedGroup = fixturesPath() + "Xcode16BuildConfigurations/Xcode16BuildConfigurations.xcodeproj/project.pbxproj"
+    return try Data(contentsOf: projectWithConfigurationFilesInSynchronizedGroup.url)
+}

From bc745ad0fbc13df143a3d2d751bad44b82054630 Mon Sep 17 00:00:00 2001
From: John Bent <theclimbingguide@gmail.com>
Date: Tue, 23 Dec 2025 14:33:29 -0500
Subject: [PATCH 4/6] Remove file headers from test project

---
 .../Xcode16BuildConfigurations/ContentView.swift           | 7 -------
 .../Xcode16BuildConfigurationsApp.swift                    | 7 -------
 2 files changed, 14 deletions(-)

diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
index 26b52dfdd..b000a7e46 100644
--- a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/ContentView.swift
@@ -1,10 +1,3 @@
-//
-//  ContentView.swift
-//  Xcode16BuildConfigurations
-//
-//  Created by John Bent on 12/23/25.
-//
-
 import SwiftUI
 
 struct ContentView: View {
diff --git a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift
index 43e1a0781..152617081 100644
--- a/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift
+++ b/Fixtures/Xcode16BuildConfigurations/Xcode16BuildConfigurations/Xcode16BuildConfigurationsApp.swift
@@ -1,10 +1,3 @@
-//
-//  Xcode16BuildConfigurationsApp.swift
-//  Xcode16BuildConfigurations
-//
-//  Created by John Bent on 12/23/25.
-//
-
 import SwiftUI
 
 @main

From 145093a87eecf94b99d7ab2faa9533c429bdd421 Mon Sep 17 00:00:00 2001
From: fortmarek <marekfort@me.com>
Date: Tue, 5 May 2026 10:52:26 +0200
Subject: [PATCH 5/6] Address review feedback on Xcode 16 build configuration
 support

- Revert unrelated `.editorconfig` indent_size change
- Split XCBuildConfiguration init into two dedicated initializers
  (legacy PBXGroup form + Xcode 16 anchor/relative-path form) to make
  the mutually-exclusive reference styles explicit and document them
- Reject partial anchor data in the decoder with DecodingError.dataCorrupted
  instead of silently dropping the field
- Fix doc-comment typos
- Add tests covering the partial-anchor-data decoder failure paths

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 .editorconfig                                 |  2 +-
 .../Configuration/XCBuildConfiguration.swift  | 74 ++++++++++++++-----
 .../XCBuildConfigurationTests.swift           | 34 +++++++++
 3 files changed, 90 insertions(+), 20 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index 51f8f62b6..0d1fce288 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -2,7 +2,7 @@ root = true
 
 [*]
 indent_style = space
-indent_size = 4
+indent_size = 2
 end_of_line = lf
 charset = utf-8
 trim_trailing_whitespace = true
diff --git a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
index c019c3ba5..43f0820e2 100644
--- a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
+++ b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
@@ -45,26 +45,45 @@ public final class XCBuildConfiguration: PBXObject {
 
     // MARK: - Init
 
-    /// Initializes a build configuration.
+    /// Initializes a build configuration whose base xcconfig (if any) lives in a ``PBXGroup``.
     ///
     /// - Parameters:
     ///   - name: build configuration name.
-    ///   - baseConfiguration: base configuration reference belonging to a group.
-    ///   - baseConfigurationAnchor: the leaf file system synchronized group that contains the base xcconfig file as a descendant.
-    ///   - baseConfigurationRelativePath: relative path from `baseConfigurationAnchor` to the base xcconfig file.
+    ///   - baseConfiguration: base xcconfig file reference belonging to a ``PBXGroup``.
     ///   - buildSettings: dictionary that contains the build settings for this configuration.
     ///
     /// - Important:
-    ///     The `baseConfiguration` parameter should be used if the configuration file belongs to a``PBXGroup``.
-    ///     If the configuration file belongs to a ``PBXFileSystemSynchronizedRootGroup``, use the `baseConfigurationAnchor`
-    ///     and `baseConfigurationRelativePath` parameters to address the file instead.
+    ///     If the base xcconfig file lives inside a ``PBXFileSystemSynchronizedRootGroup`` (Xcode 16+), use
+    ///     ``init(name:baseConfigurationAnchor:baseConfigurationRelativePath:buildSettings:)`` instead. The two
+    ///     reference styles are mutually exclusive: a single configuration cannot use both `baseConfiguration` and
+    ///     the anchor/relative-path pair.
     public init(name: String,
                 baseConfiguration: PBXFileReference? = nil,
-                baseConfigurationAnchor: PBXFileSystemSynchronizedRootGroup? = nil,
-                baseConfigurationRelativePath: String? = nil,
                 buildSettings: BuildSettings = [:]) {
         baseConfigurationReference = baseConfiguration?.reference
-        baseConfigurationReferenceAnchor = baseConfigurationAnchor?.reference
+        self.buildSettings = buildSettings
+        self.name = name
+        super.init()
+    }
+
+    /// Initializes a build configuration whose base xcconfig lives inside a ``PBXFileSystemSynchronizedRootGroup``.
+    ///
+    /// - Parameters:
+    ///   - name: build configuration name.
+    ///   - baseConfigurationAnchor: the file system synchronized root group that contains the base xcconfig file as a descendant.
+    ///   - baseConfigurationRelativePath: relative path from `baseConfigurationAnchor` to the base xcconfig file.
+    ///   - buildSettings: dictionary that contains the build settings for this configuration.
+    ///
+    /// - Important:
+    ///     This initializer is for the Xcode 16+ representation, where xcconfig files inside a synchronized root
+    ///     group are referenced by an anchor + relative path pair. If the base xcconfig file belongs to a regular
+    ///     ``PBXGroup``, use ``init(name:baseConfiguration:buildSettings:)`` instead. The two reference styles are
+    ///     mutually exclusive: a single configuration cannot use both `baseConfiguration` and the anchor/relative-path pair.
+    public init(name: String,
+                baseConfigurationAnchor: PBXFileSystemSynchronizedRootGroup,
+                baseConfigurationRelativePath: String,
+                buildSettings: BuildSettings = [:]) {
+        baseConfigurationReferenceAnchor = baseConfigurationAnchor.reference
         baseConfigurationReferenceRelativePath = baseConfigurationRelativePath
         self.buildSettings = buildSettings
         self.name = name
@@ -85,15 +104,32 @@ public final class XCBuildConfiguration: PBXObject {
         let objects = decoder.context.objects
         let objectReferenceRepository = decoder.context.objectReferenceRepository
         let container = try decoder.container(keyedBy: CodingKeys.self)
-        // configuration files may be reference by either a pair of PBXFileSystemSynchronizedRootGroup and relative path (Xcode 16)
-        // or a PBXFileReference if the file belongs to a PBXGroup
-        if let baseConfigurationReferenceAnchor: String = try container.decodeIfPresent(.baseConfigurationReferenceAnchor),
-           let baseConfigurationReferenceRelativePath: String = try container.decodeIfPresent(.baseConfigurationReferenceRelativePath)
-        {
-            self.baseConfigurationReferenceAnchor = objectReferenceRepository.getOrCreate(reference: baseConfigurationReferenceAnchor, objects: objects)
-            self.baseConfigurationReferenceRelativePath = baseConfigurationReferenceRelativePath
-        } else if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
-            self.baseConfigurationReference = objectReferenceRepository.getOrCreate(reference: baseConfigurationReference, objects: objects)
+        // Configuration files may be referenced either by a pair of (PBXFileSystemSynchronizedRootGroup, relative path)
+        // when the xcconfig lives inside a synchronized root group (Xcode 16+), or by a PBXFileReference when it
+        // belongs to a regular PBXGroup. The anchor and relative-path keys are emitted together by Xcode; treat one
+        // without the other as a corrupt pbxproj rather than silently dropping the field.
+        let anchorReference: String? = try container.decodeIfPresent(.baseConfigurationReferenceAnchor)
+        let anchorRelativePath: String? = try container.decodeIfPresent(.baseConfigurationReferenceRelativePath)
+        switch (anchorReference, anchorRelativePath) {
+        case let (anchorReference?, anchorRelativePath?):
+            baseConfigurationReferenceAnchor = objectReferenceRepository.getOrCreate(reference: anchorReference, objects: objects)
+            baseConfigurationReferenceRelativePath = anchorRelativePath
+        case (nil, nil):
+            if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
+                self.baseConfigurationReference = objectReferenceRepository.getOrCreate(reference: baseConfigurationReference, objects: objects)
+            }
+        case (_?, nil):
+            throw DecodingError.dataCorruptedError(
+                forKey: .baseConfigurationReferenceRelativePath,
+                in: container,
+                debugDescription: "baseConfigurationReferenceAnchor is present but baseConfigurationReferenceRelativePath is missing."
+            )
+        case (nil, _?):
+            throw DecodingError.dataCorruptedError(
+                forKey: .baseConfigurationReferenceAnchor,
+                in: container,
+                debugDescription: "baseConfigurationReferenceRelativePath is present but baseConfigurationReferenceAnchor is missing."
+            )
         }
         buildSettings = try container.decode(BuildSettings.self, forKey: .buildSettings)
         name = try container.decode(.name)
diff --git a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
index 64d357f8a..9eacd60d3 100644
--- a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
+++ b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
@@ -100,6 +100,40 @@ final class XCBuildConfigurationTests: XCTestCase {
         XCTAssertNotNil(subject.baseConfigurationReferenceRelativePath)
     }
 
+    func test_decoding_fails_whenAnchorPresentWithoutRelativePath() throws {
+        let dictionary: [String: Any] = [
+            "baseConfigurationReferenceAnchor": "anchorRef",
+            "buildSettings": [:],
+            "name": "Debug",
+            "reference": "reference",
+        ]
+        let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
+
+        XCTAssertThrowsError(try XcodeprojJSONDecoder().decode(XCBuildConfiguration.self, from: data)) { error in
+            guard case let DecodingError.dataCorrupted(context) = error else {
+                return XCTFail("Expected DecodingError.dataCorrupted, got \(error).")
+            }
+            XCTAssertEqual(context.codingPath.last?.stringValue, "baseConfigurationReferenceRelativePath")
+        }
+    }
+
+    func test_decoding_fails_whenRelativePathPresentWithoutAnchor() throws {
+        let dictionary: [String: Any] = [
+            "baseConfigurationReferenceRelativePath": "Configs/DevConfig.xcconfig",
+            "buildSettings": [:],
+            "name": "Debug",
+            "reference": "reference",
+        ]
+        let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
+
+        XCTAssertThrowsError(try XcodeprojJSONDecoder().decode(XCBuildConfiguration.self, from: data)) { error in
+            guard case let DecodingError.dataCorrupted(context) = error else {
+                return XCTFail("Expected DecodingError.dataCorrupted, got \(error).")
+            }
+            XCTAssertEqual(context.codingPath.last?.stringValue, "baseConfigurationReferenceAnchor")
+        }
+    }
+
     private func testDictionary() -> [String: Any] {
         [
             "baseConfigurationReference": "baseConfigurationReference",

From bb2885256bc9f2a5709e7781cd1d86d5e1e06fc9 Mon Sep 17 00:00:00 2001
From: fortmarek <marekfort@me.com>
Date: Tue, 5 May 2026 10:59:01 +0200
Subject: [PATCH 6/6] Revert decoder partial-anchor-data error

Fall back to the original behaviour: if only one of `baseConfigurationReferenceAnchor`
and `baseConfigurationReferenceRelativePath` is present, silently skip them and
try `baseConfigurationReference` instead, rather than throwing.

Drop the two tests that asserted the removed throwing behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 .../Configuration/XCBuildConfiguration.swift  | 32 +++++------------
 .../XCBuildConfigurationTests.swift           | 34 -------------------
 2 files changed, 8 insertions(+), 58 deletions(-)

diff --git a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
index 43f0820e2..ac4d62f9e 100644
--- a/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
+++ b/Sources/XcodeProj/Objects/Configuration/XCBuildConfiguration.swift
@@ -106,30 +106,14 @@ public final class XCBuildConfiguration: PBXObject {
         let container = try decoder.container(keyedBy: CodingKeys.self)
         // Configuration files may be referenced either by a pair of (PBXFileSystemSynchronizedRootGroup, relative path)
         // when the xcconfig lives inside a synchronized root group (Xcode 16+), or by a PBXFileReference when it
-        // belongs to a regular PBXGroup. The anchor and relative-path keys are emitted together by Xcode; treat one
-        // without the other as a corrupt pbxproj rather than silently dropping the field.
-        let anchorReference: String? = try container.decodeIfPresent(.baseConfigurationReferenceAnchor)
-        let anchorRelativePath: String? = try container.decodeIfPresent(.baseConfigurationReferenceRelativePath)
-        switch (anchorReference, anchorRelativePath) {
-        case let (anchorReference?, anchorRelativePath?):
-            baseConfigurationReferenceAnchor = objectReferenceRepository.getOrCreate(reference: anchorReference, objects: objects)
-            baseConfigurationReferenceRelativePath = anchorRelativePath
-        case (nil, nil):
-            if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
-                self.baseConfigurationReference = objectReferenceRepository.getOrCreate(reference: baseConfigurationReference, objects: objects)
-            }
-        case (_?, nil):
-            throw DecodingError.dataCorruptedError(
-                forKey: .baseConfigurationReferenceRelativePath,
-                in: container,
-                debugDescription: "baseConfigurationReferenceAnchor is present but baseConfigurationReferenceRelativePath is missing."
-            )
-        case (nil, _?):
-            throw DecodingError.dataCorruptedError(
-                forKey: .baseConfigurationReferenceAnchor,
-                in: container,
-                debugDescription: "baseConfigurationReferenceRelativePath is present but baseConfigurationReferenceAnchor is missing."
-            )
+        // belongs to a regular PBXGroup.
+        if let baseConfigurationReferenceAnchor: String = try container.decodeIfPresent(.baseConfigurationReferenceAnchor),
+           let baseConfigurationReferenceRelativePath: String = try container.decodeIfPresent(.baseConfigurationReferenceRelativePath)
+        {
+            self.baseConfigurationReferenceAnchor = objectReferenceRepository.getOrCreate(reference: baseConfigurationReferenceAnchor, objects: objects)
+            self.baseConfigurationReferenceRelativePath = baseConfigurationReferenceRelativePath
+        } else if let baseConfigurationReference: String = try container.decodeIfPresent(.baseConfigurationReference) {
+            self.baseConfigurationReference = objectReferenceRepository.getOrCreate(reference: baseConfigurationReference, objects: objects)
         }
         buildSettings = try container.decode(BuildSettings.self, forKey: .buildSettings)
         name = try container.decode(.name)
diff --git a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
index 9eacd60d3..64d357f8a 100644
--- a/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
+++ b/Tests/XcodeProjTests/Objects/Configuration/XCBuildConfigurationTests.swift
@@ -100,40 +100,6 @@ final class XCBuildConfigurationTests: XCTestCase {
         XCTAssertNotNil(subject.baseConfigurationReferenceRelativePath)
     }
 
-    func test_decoding_fails_whenAnchorPresentWithoutRelativePath() throws {
-        let dictionary: [String: Any] = [
-            "baseConfigurationReferenceAnchor": "anchorRef",
-            "buildSettings": [:],
-            "name": "Debug",
-            "reference": "reference",
-        ]
-        let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
-
-        XCTAssertThrowsError(try XcodeprojJSONDecoder().decode(XCBuildConfiguration.self, from: data)) { error in
-            guard case let DecodingError.dataCorrupted(context) = error else {
-                return XCTFail("Expected DecodingError.dataCorrupted, got \(error).")
-            }
-            XCTAssertEqual(context.codingPath.last?.stringValue, "baseConfigurationReferenceRelativePath")
-        }
-    }
-
-    func test_decoding_fails_whenRelativePathPresentWithoutAnchor() throws {
-        let dictionary: [String: Any] = [
-            "baseConfigurationReferenceRelativePath": "Configs/DevConfig.xcconfig",
-            "buildSettings": [:],
-            "name": "Debug",
-            "reference": "reference",
-        ]
-        let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
-
-        XCTAssertThrowsError(try XcodeprojJSONDecoder().decode(XCBuildConfiguration.self, from: data)) { error in
-            guard case let DecodingError.dataCorrupted(context) = error else {
-                return XCTFail("Expected DecodingError.dataCorrupted, got \(error).")
-            }
-            XCTAssertEqual(context.codingPath.last?.stringValue, "baseConfigurationReferenceAnchor")
-        }
-    }
-
     private func testDictionary() -> [String: Any] {
         [
             "baseConfigurationReference": "baseConfigurationReference",
