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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions