CocoaPods / Xcodeproj

Create and modify Xcode projects from Ruby.
http://rubygems.org/gems/xcodeproj
MIT License
2.35k stars 454 forks source link

Touch project file & Buildfile references become (null) references #574

Open claybridges opened 6 years ago

claybridges commented 6 years ago

We updated to CocoaPods 1.5.0. Having done this, it seems like whenever we touch our project.pbxproj files, references like these:

75223EE0200D46CB00E54736 /* BuildFile in Headers */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (Public, ); }; };

Turn into these

75223EE0200D46CB00E54736 /* (null) in Headers */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (Public, ); }; };

We can fix with

pod deintegrate
pod install

However, this is generating a lot of unnecessary and obfuscating noise in our project file.

See possibly related #248.

andrewdmontgomery commented 2 years ago

The root of the problem

The root cause of this problem appears to have been a FileReference object that was removed from the project (by Xcodeproj) without also removing existing BuildFile objects that referenced it.

That means that a BuildFile entry without a FileReference is meaningless. That's what we're looking at here: orphaned BuildFile entries in our project file. They appear to be inert. In fact, we would probably would never have noticed them if it weren't for a slight difference in how Xcode and Xcodeproj handled them.

Handling orphans

These orphaned PBXBuildFile entries in the project file are very recognizable once you know what to look for:

F54BBB842787606B00A10CEE /* MyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54BBB832787606B00A10CEE /* MyViewController.swift */; };

F567366F26D8052C0084ECEF /* BuildFile in Sources */ = {isa = PBXBuildFile; };

The first line is fine. The second line is the problem:

  1. Both are PBXBuildFile entries (e.g. isa = PBXBuildFile;)
  2. The second entry is missing a fileRef = [UUID]; attribute

The second line is an example of an orphaned BuildFile object in the project. The problem for us is that Xcode and Xcodeproj handle this line slightly differently. When the name of the FileReference is missing (because the underlying FileReference is missing):

So we see flapping between the two, as Xcode writes it one way, and then Xcodeproj writes it the other way.

Root cause fixed (not yet released), existing orphans will remain after fix

The source of these orphaned BuildFile entries appears to have been Xcodeproj. It was not removing BuildFile objects from the project when it removed FileReferences.

The underlying issue appears to have been fixed in #861 (which as of now, hasn't shipped in a new version yet).

Once that is released, and we update, any projects using this patched version of Xcodeproj won't produce any new orphaned BuildFile objects. But any existing objects will not be cleaned up by this fix.

This StackOverflow post suggests a simple way to remove some of the most commonly reported orphaned entries:

#!/bin/sh
sed -i '' '/(null) in Sources /d' ProjectName.xcodeproj/project.pbxproj
sed -i '' '/(null) in Resources /d' ProjectName.xcodeproj/project.pbxproj
sed -i '' '/(null) in Frameworks /d' ProjectName.xcodeproj/project.pbxproj

Note that this script assumes that the project file was most recently updated by Xcode, which results in (null) entries. If the project file was last updated by Xcodeproj (or CocoaPods via Xcodeproj), then these lines will show BuildFile instead of (null).

Given the nature of the root problem, it might be safer to write a short ruby script that used Xcodeproj to find PBXBuildFile entires that are missing a PBXFileReference, or some similar check, and remove them. I may have some time this week to work on that.