yonaskolb / XcodeGen

A Swift command line tool for generating your Xcode project
MIT License
7.01k stars 819 forks source link

Consistency issue: unexpected multiple parents for object `xcconfig` #771

Open chrisballinger opened 4 years ago

chrisballinger commented 4 years ago

When using custom xcconfigs at the project level, it seems that Xcodegen generates an orphaned group for the xcconfigs, which causes CocoaPods to fail until the project file is "fixed" by Xcode.

For example, given the following project.yml:

name: PRODUCTNAME
options:
  bundleIdPrefix: com.rightpoint
packages:
  BonMot:
    url: https://github.com/Rightpoint/BonMot.git
    from: 5.5.0
  Anchorage:
    url: https://github.com/Rightpoint/Anchorage.git
    from: 4.4.0
configs:
  Debug: debug
  Develop: release
  Sprint: release
  AppStore: release
configFiles:
  Debug: PRODUCTNAME/Resources/xcconfig/Debug.xcconfig
  Develop: PRODUCTNAME/Resources/xcconfig/Develop.xcconfig
  Sprint: PRODUCTNAME/Resources/xcconfig/Sprint.xcconfig
  AppStore: PRODUCTNAME/Resources/xcconfig/AppStore.xcconfig
targets:
  PRODUCTNAME:
    type: application
    platform: iOS
    deploymentTarget: "12.0"
    sources: [PRODUCTNAME]
    dependencies:
      - target: Services
      - package: BonMot
      - package: Anchorage
  PRODUCTNAMETests:
    type: bundle.unit-test
    platform: iOS
    deploymentTarget: "12.0"
    sources: [PRODUCTNAMETests]
    dependencies:
      - target: Services
  Services:
    type: framework
    platform: iOS
    sources: [Services]

It will generate an Xcode project that is deemed invalid by the Xcodeproj gem:

$ bundle exec pod install
...
RuntimeError - [Xcodeproj] Consistency issue: unexpected multiple parents for object `xcconfig`: [<PBXGroup path=`Resources` UUID=`42D132E167CA6DBCCDED2615`>, <PBXGroup UUID=`65C752E3E9E65C0DF852998A`>]

Curiously, if you simply open the PRODUCTNAME.xcodeproj in Xcode, change any setting back and forth, and then run pod install again, it succeeds. It looks like this is because Xcode does some sort of error correction on the generated project file. Here's an interesting part of the diff.

-                               F1BE11E77973887FDB838436 /* xcconfig */,

Although this is sort of an issue at the intersection of XcodeGen and CocoaPods - because allowing Xcode to auto-fix the project file fixes the CocoaPods/Xcodeproj issue - I think that ultimately this is a defect in XcodeGen.

Workaround

swiftcrossing commented 4 years ago

I came across the same issue today when trying to build my project via fastlane.

After playing around with the xcodeproj file in a text editor, I found that the group/folder containing the xcconfig files is referenced 3 times: once as a folder in its actual location, once as a folder of the root directory and once as a reference to the group itself. The conflict occurs because of the first two references. Build tools are expecting the folder to only have one location associated with it, but it has two. Xcode is able to figure out what is going on and resolve this issue for us when it runs it magic xcodeproj-fixing-wizardry.

As for xcodegen, it looks like there are 2 options to correct this inconsistency: A: Deleting the line that references the folder in its actual location or B: Deleting the line that references the folder in the root director AND changing the reference path and name so that it matches the conventional style of a folder being referenced by its actual location

Option A results in the folder only appearing in the root director while Option B results in the folder only appearing in its original location.

As a fix for this issue, in order to maintain current behavior, I believe Option A could be adopted by default when running xcodegen. Then maybe as a nice to have feature, a command line option to reference xcconfig files in their actual location rather than the project root (Option B) could be provided.

It looks like XcodeGen uses some other third party libraries like XcodeProj and PathKit under the hood, so I'm not sure if this is an issue that needs to be addressed by or one of these other tools. Any thoughts would be appreciated.

18373D73393274A344530838 /* SupportingFiles */ = {
    isa = PBXGroup;
    children = (
        E624C8B075B080666BEF9FA5 /* XCConfigFiles */,   <------- A: Delete this line only
    );
    path = SupportingFiles;
    sourceTree = "<group>";
};
D0D7B7F1EA0F1CA8BD7E631F = {
    isa = PBXGroup;
    children = (
        EBCF180E7D7738F63351A00B /* MyProj */,
        E624C8B075B080666BEF9FA5 /* XCConfigFiles */,   <------- B: Delete this line AND
        123665637EED67265FB37960 /* Frameworks */,
        0F7D59E5477B76E31FB6A006 /* Products */,
    );
    indentWidth = 2;
    sourceTree = "<group>";
    tabWidth = 2;
    usesTabs = 0;
};
E624C8B075B080666BEF9FA5 /* XCConfigFiles */ = {
    isa = PBXGroup;
    children = (
        65ACCD8C97D4F8E1F2487DC4 /* MyProj-Debug.xcconfig */,
        46A23E31D0FAC1775EBC7CD5 /* MyProj-Release.xcconfig */,
    );
    name = XCConfigFiles;                              <------- B: Delete this line AND
    path = MyProj/SupportingFiles/XCConfigFiles;       <------- B: Change this line to `path = XCConfigFiles;`
    sourceTree = "<group>";
};