Xcode Project Linter (xcprojectlint)
This project provides a security blanket, ensuring neither your co-workers, nor
git screw up your Xcode project file. Some of the settings are arguably a matter
of personal taste. Fortunately, each option can be enabled separately.
currently supports these checks:
This mode ensures there are no settings configured at the project level, instead encouraging the use of xcconfig files.
This mode ensures the project references reflect actual file system locations. There are some occasions where you may not be able to exactly map a folder to disk (Frameworks and Products are common examples). For this, there is an additional parameter you can pass:
--skip-folders, followed by a list of folders to ignore.
This mode finds file references in the project which are not backed by files.
This mode reports groups that contain no additional items.
This mode ensures the project files and folders are in proper order.
For convenience, this mode runs all of the above tests.
When a failing condition is detected, as much useful context as possible is
STDOUT, enabling Xcode to display the errors, in place. Further, it
optionally can return
EX_SOFTWARE, preventing the build from succeeding until
the problem is addressed.
Building the Code
xcprojectlint tool, run
$ swift package update $ make build
Huh? A Makefile?!?
make to hide several shortcomings of the current state of Swift
Package Manager. First off, it has no notion of Resources, which we need for our
$ make test
to build the test target, copy in the test fixtures, then run the tests.
Second up, the static linking option is documented to be broken, and indeed, it is.
$ make release
passes the optional arguments that make static linked binaries actually happen.
For completeness, there are also wrappers for
Debugging in Xcode
If you want to debug from Xcode, you can run
make xcode to generate the
project file, and then add a Copy Files build phase, configured like this:
as a build script phase:
bin/xcprojectlint --report error --validations all --project $PROJECT_FILE_PATH
as a shell command:
xcprojectlint --report error --validations files-exist-on-disk items-in-alpha-order --project /tmp/Example/Example.xcproject
The Nitty Gritty
xcprojectlint is operating on an undocumented file format. Years of looking at broken
git merges has given us a reasonable confidence that we know how the parts all
work together. That said, it is still a best guess, so there may be oversights.
Fortunately, these linting operations are read-only, and will not modify your
Each run starts by parsing the project file into a series of collections, which represent our understanding of how a project file is composed. It uses both the property list structure, and the comments Xcode writes into the project to assemble its data. Afterwards, xcprojectlint applies validity tests to the extracted collections, ensuring that the rules specified are met.
Clues to Fix By
As much as possible, xcprojectlint will attempt to tell you how to locate the problem. It’ll tell you which build configuration has settings, what the expected order of a group is, and whatever else it can squeeze out of the available context. Sometimes, it’ll even tell you the line number in the project file to look at. This is great, but do not attempt to view the project within Xcode. Terrible, terrible things will happen. Instead, use your favorite text editor to peer inside.
Build Settings Externalized
We iterate all the
BuildConfigurationblobs, and investigate their
BuildSettingsentry. Empty settings are A-OK. Any found settings are in error.
Disk Layout Matches Project
This test grabs the
MainGroupout of the project, then recursively traverses the children. If the child node is a file, we retrieve the
FileReferenceby id, then check for a
namevalue. The presence of a name indicates this file reference does not have a matching file on disk.
Files Exist on Disk
This uses a similar recursion to the Layout test, but instead of investigating the
namevalue, it builds a URL to where the file should appear on disk. This is done by assembling the path that led to the file, then appending that to a path derived from the project’s path on disk, then finally testing for the presence of a file at that location.
One of the simpler tests. We again recurse the
MainGroup, but this time look for entries that have zero children.
Items in Alpha Order
We expect our project nodes to contain alphabetized Folders, followed by alphabetized Files. We check on that by again recursing the groups, and at each level sifting the entries into
allNames. We sort the groups and files, contatenate them, then compare that to the list of everything.
We welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source Project managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to the terms below. Except for the rights granted in this Agreement to American Express and to recipients of software distributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions. Please fill out the Agreement.
Please feel free to open pull requests and see CONTRIBUTING.md for commit formatting details.
Any contributions made under this project will be governed by the Apache License 2.0.
Code of Conduct
This project adheres to the American Express Community Guidelines. By participating, you are expected to honor these guidelines.