Touch project file & Buildfile references become (null) references
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.
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.
- a
PBXFileReferenceobject is a reference to an actual file on disk, and is how Xcode tracks which files should appear on the left panel (among other things) - a
PBXBuildFileobject is meant to wrap an existingPBXFileReferenceobject, and is created when a FileReference is added to a Target (for tracking file specific build information)
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:
- Both are PBXBuildFile entries (e.g.
isa = PBXBuildFile;) - 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):
- Xcode (presumably using String interpellation of a nil object) writes
(null) in Headers,(null) in Sources,(null) in Frameworks, etc. - Xcodeproj uses the
Classof the object (when the name is missing), producingBuildFile in Headers,BuildFile in Sources,BuildFile in Frameworks
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.