Skip to content

Preserve Swift Package trait selections across read/write #1113

@chigichan24

Description

@chigichan24

Summary

Xcode 26.4+ writes Swift Package Manager traits (SE-0450) into project.pbxproj as traits = ( ... ); entries on XCRemoteSwiftPackageReference and XCLocalSwiftPackageReference. Stock XcodeProj 9.11.0 has no traits field on these types, so any tool that loads such a project and calls XcodeProj.write() silently discards the user's trait selection. On next open, Xcode sees no traits key and falls back to default traits re-enabling features the user opted out of, or pulling back frameworks they excluded (e.g. a NoUIFramework selection that kept UIKit/AppKit out would quietly come back on).

pbxproj format in the wild

Real-world examples:

Confirmed introduced in Xcode 26.4 (stable, currently 26.4.1); not emitted by 26.3 or earlier.

Reproducer

https://github.com/chigichan24/XcodeProj-MinimalProject

git clone https://github.com/chigichan24/XcodeProj-MinimalProject
cd XcodeProj-MinimalProject
./compare.sh

The Stock/ side (pinned to XcodeProj exact 9.11.0) prints:

fixture has 5 trait-related lines ...
after load -> write: 0 trait-related lines
Result: traits preserved in output pbxproj = NO

The Branch/ side (patch applied) preserves them and passes every round-trip check.

Impact

  • Downstream generators built on XcodeProj (notably feat: Package traits yonaskolb/XcodeGen#1585) cannot emit traits while this field is absent from the public model. Users of such generators today are either stuck without traits or hand-committing the generated .xcodeproj to preserve them
    (as the Sentry team does).

Proposed direction

Add traits: [String]? to XCRemoteSwiftPackageReference and XCLocalSwiftPackageReference. Keep nil vs [] distinct (SE-0450 treats traits: [] as "disable default traits"). No public-API change for projects not using traits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions